PageSourceSearch

https://www.hussde.com/assets/CourseHome-CSMcsseN.js

js hussde.com collected 2026-09-29 02:04:35 UTC 202,872 bytes, 12 lines download raw bytes

1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/HwpViewer-oqnOEjya.js","assets/index-CitDxPDD.js","assets/index-DC3VeJA_.css","assets/rhwp-Dnsx4au7.js","assets/HwpViewer-Dkb7rUZa.css"])))=>i.map(i=>d[i]);
2import{r as t,j as e,d as gs,M as ri,b as Ce,ac as li,v as fs,_ as ci,O as tn,ad as oi,e as di,ae as Js,h as ui,u as mi,f as hi,a9 as pi,af as xi}from"./index-CitDxPDD.js";import{L as gi}from"./LMSLayout-BNIclSg2.js";import{u as fi,C as vi}from"./CourseHome-w3-VxeQW.js";import{l as I}from"./lmsService-B6qvu0E2.js";import{k as ji,p as Lt,a as Vt}from"./dateUtils-BPzYxBeH.js";import{a as Us}from"./DashVideoPlayer-DFhs29S-.js";import"./UniversalVideoPlayer-OT6UeSfc.js";import{r as bi}from"./index-DNK-50gv.js";import{P as aa}from"./PDFViewer-D39MJgCp.js";import{o as yi,O as _i,i as Ni}from"./officeDocs-z3j-8PKU.js";import{w as Vn,p as ki}from"./streaming-BNUVWwHh.js";import{I as ce}from"./LmsIcons-B1jytojs.js";import{d as ia,b as ra}from"./blockTypes-SXNrow-N.js";import{V as wi}from"./VideoBlockGradeModal-BsPbci9-.js";import Si from"./CourseSyllabusEditor-CVWQLBHR.js";/* empty css                   */import"./LMSHeader-BkpnkaSX.js";import"./LMSSidebar-CkyrX723.js";import"./LearningActivityIcon-Cz49P-1A.js";import"./xlsx-BfjHtLxh.js";import"./VideoBlockGradeModal-B-Roqn8D.js";import"./TiptapEditor-CXjQtmf_.js";import"./TiptapEditor-Bs-meWAo.js";import"./with-selector-CPBoAPpH.js";import"./volumeCheck-Bnhu1qOB.js";import"./handsontable.full.min-1NS6hAcY.js";import"./base-5bYaROZj.js";import"./purify.es-CGs5VtEq.js";import"./registry-DyPHYmpx.js";const Ci=({isOpen:n,onClose:l,onSubmit:h,lessonId:d})=>{const[v,r]=t.useState("edit"),[i,y]=t.useState({title:"",messageAlert:!1,videoType:"chunk",useAttendance:!0,attendanceStart:new Date().toISOString().slice(0,16),attendanceEnd:new Date(Date.now()+720*60*60*1e3).toISOString().slice(0,16),progress:90,isPublic:!0}),[T,$]=t.useState(!1),[F,A]=t.useState(!0),[N,b]=t.useState("title");if(t.useEffect(()=>{const g=B=>{B.key==="Escape"&&n&&k()};return n&&document.addEventListener("keydown",g),()=>{document.removeEventListener("keydown",g)}},[n]),!n)return null;const k=()=>{y({title:"",messageAlert:!1,videoType:"chunk",useAttendance:!0,attendanceStart:new Date().toISOString().slice(0,16),attendanceEnd:new Date(Date.now()+720*60*60*1e3).toISOString().slice(0,16),progress:90,isPublic:!0}),r("edit"),$(!1),A(!0),l()},w=g=>{g.preventDefault(),h(i),k()},p=(g,B)=>{y(W=>({...W,[g]:B}))},K=g=>{switch(g){case"title":return{completed:!!i.title.trim(),required:!0};case"message":return{completed:!0,required:!1};case"video":return{completed:i.videoType==="chunk"?!!i.videoFile:!!i.youtubeUrl?.trim(),required:!0};case"attendance":return{completed:!0,required:!1};case"caption":return{completed:!0,required:!1};case"progress":return{completed:i.progress>0,required:!1};case"public":return{completed:!0,required:!1};default:return{completed:!1,required:!1}}},Z=g=>{b(g),document.querySelectorAll(".form-row").forEach(W=>{W.classList.remove("highlighted")});const B=document.getElementById(`section-${g}`);B&&(B.classList.add("highlighted"),setTimeout(()=>{B.classList.remove("highlighted")},3e3))},Q=[{id:"title",label:"제목"},{id:"message",label:"메시지 알림"},{id:"video",label:"동영상 업로드"},{id:"attendance",label:"출석인정기간"},{id:"caption",label:"자막 추가"},{id:"progress",label:"학습인정 진도율"},{id:"public",label:"공개여부"}];return e.jsx("div",{className:"video-modal-overlay",children:e.jsx("div",{className:"video-modal-wrapper",children:e.jsxs("div",{className:"modal-content video-modal",children:[e.jsxs("header",{className:"modal-header",children:[e.jsx("h2",{className:"modal-title video",children:"동영상 입력"}),e.jsx("button",{className:"modal-close",onClick:k,children:e.jsx("svg",{stroke:"currentColor",fill:"currentColor",strokeWidth:"0",viewBox:"0 0 24 24",height:"1em",width:"1em",children:e.jsx("path",{fill:"none",stroke:"#000",strokeWidth:"2",d:"M3,3 L21,21 M3,21 L21,3"})})})]}),e.jsxs("div",{className:"modal-body",children:[e.jsxs("div",{className:"modal-tabs",children:[e.jsx("button",{className:v==="edit"?"active":"",onClick:()=>r("edit"),children:"수정"}),e.jsx("button",{className:v==="stats"?"active":"",onClick:()=>r("stats"),children:"학습현황 및 평가"})]}),v==="edit"&&e.jsxs("div",{className:"edit-content",children:[e.jsx("div",{className:"form-sidebar",children:e.jsx("div",{className:"sidebar-sections",children:Q.map(g=>{const B=K(g.id);return e.jsxs("button",{type:"button",className:`sidebar-section-btn ${N===g.id?"active":""} ${B.required?"required":""}`,onClick:()=>
2Z(g.id),title:g.label,children:[e.jsx("div",{className:"section-label",children:g.label}),e.jsx("div",{className:"section-status",children:B.required&&e.jsx("span",{className:"required-badge",children:"*"})})]},g.id)})})}),e.jsxs("div",{className:"edit-form-section",children:[e.jsx("div",{className:"form-header",children:e.jsxs("button",{type:"button",className:"preview-toggle-btn",onClick:()=>A(!F),children:[F?"미리보기 숨기기":"학습자 화면 미리보기"," 👁️"]})}),e.jsx("form",{onSubmit:w,className:"video-form",id:"video-form",children:e.jsxs("div",{className:"form-section",children:[e.jsxs("div",{className:"form-row",id:"section-title",children:[e.jsx("h3",{className:"form-label required",children:"제목"}),e.jsx("div",{className:"form-content",children:e.jsx("input",{type:"text",value:i.title,onChange:g=>p("title",g.target.value),placeholder:"제목을 입력해주세요.",required:!0,className:"form-input"})})]}),e.jsxs("div",{className:"form-row",id:"section-message",children:[e.jsx("h3",{className:"form-label",children:"메시지 알림"}),e.jsx("div",{className:"form-content",children:e.jsxs("label",{className:"checkbox-wrapper",children:[e.jsx("input",{type:"checkbox",checked:i.messageAlert,onChange:g=>p("messageAlert",g.target.checked)}),e.jsx("span",{className:"checkbox-mark"}),e.jsxs("p",{children:["허용 ",e.jsx("i",{children:"(푸시 알림과 이메일 알림을 같이 보냅니다)"})]})]})})]}),e.jsxs("div",{className:"form-row",id:"section-video",children:[e.jsx("h3",{className:"form-label required",children:"동영상 업로드"}),e.jsxs("div",{className:"form-content",children:[e.jsxs("div",{className:"radio-group",children:[e.jsxs("label",{className:"radio-wrapper",children:[e.jsx("input",{type:"radio",name:"videoType",value:"chunk",checked:i.videoType==="chunk",onChange:g=>p("videoType",g.target.value)}),e.jsx("span",{className:"radio-mark"}),e.jsx("p",{children:"업로드"})]}),e.jsxs("label",{className:"radio-wrapper",children:[e.jsx("input",{type:"radio",name:"videoType",value:"youtube",checked:i.videoType==="youtube",onChange:g=>p("videoType",g.target.value)}),e.jsx("span",{className:"radio-mark"}),e.jsx("p",{children:"유튜브"})]})]}),i.videoType==="chunk"?e.jsxs("div",{className:"file-upload",children:[e.jsx("input",{type:"file",accept:"video/mp4",onChange:g=>p("videoFile",g.target.files?.[0]),className:"file-input"}),e.jsx("div",{className:"help-text",children:e.jsx("p",{children:"업로드 최대 용량은 1.2GB이고, MP4 파일만 업로드가 가능합니다."})})]}):e.jsx("div",{className:"youtube-input",children:e.jsx("input",{type:"url",placeholder:"유튜브 URL을 입력하세요",value:i.youtubeUrl||"",onChange:g=>p("youtubeUrl",g.target.value),className:"form-input"})})]})]}),e.jsxs("div",{className:"form-row",id:"section-attendance",children:[e.jsx("h3",{className:"form-label",children:"출석인정기간"}),e.jsxs("div",{className:"form-content",children:[e.jsxs("label",{className:"radio-wrapper",children:[e.jsx("input",{type:"radio",checked:i.useAttendance,onChange:g=>p("useAttendance",!0)}),e.jsx("span",{className:"radio-mark"}),e.jsx("p",{children:"사용함"})]}),i.useAttendance&&e.jsxs("div",{className:"datetime-range",children:[e.jsxs("div",{className:"datetime-group",children:[e.jsx("h4",{children:"시작 일시"}),e.jsx("input",{type:"datetime-local",value:i.attendanceStart,onChange:g=>p("attendanceStart",g.target.value),className:"datetime-input"})]}),e.jsxs("div",{className:"datetime-group",children:[e.jsx("h4",{children:"종료 일시"}),e.jsx("input",{type:"datetime-local",value:i.attendanceEnd,onChange:g=>p("attendanceEnd",g.target.value),className:"datetime-input"})]})]}),e.jsxs("label",{className:"radio-wrapper",children:[e.jsx("input",{type:"radio",checked:!i.useAttendance,onChange:g=>p("useAttendance",!1)}),e.jsx("span",{className:"radio-mark"}),e.jsx("p",{children:"사용안함"})]})]})]}),e.jsxs("div",{className:"form-row",id:"section-caption",children:[e.jsx("h3",{className:"form-label",children:"자막 추가"}),e.jsxs("div",{className:"form-content",children:[e.jsx("input",{type:"file",accept:".srt,.vtt",onChange:g=>p("captionFile",g.target.files?.[0]),className:"file-input"}),e.jsx("p",{className:"help-text",children:"허용된 확장자: srt, vtt"})]})]}),e.jsxs("div",{className:"form-row",id:"section-progress",children:[e.jsx("h3",{className:"form-label",children:"학습인정 진도율(%)"}),e.jsx("div",{className:"form-content",children:e.jsx("input",{type:"number",value:i.progress,onChange:g=>p("progress",parseInt(g.target.value)),min:"0",max:"100",className:"form-input short"})})]}),e.jsxs("div",{className:"form-row",id:"section-public",children:[e.jsx("h3",{className:"form-label",children:"공개여부"}),e.jsx("div",{className:"form-content",children:e.jsxs("div",{className:"radio-group",children:[e.jsxs("label",{className:"radio-wrapper",children:[e.jsx("input",{type:"radio",checked:i.isPublic,onChange:g=>p("isPublic",!0)}),e.jsx("span",{className:"radio-mark"}),e.jsx("p",{children:"공개"})]}),e.jsxs("label",{className:"radio-wrapper",children:[e.jsx("input",{type:"radio",checked:!i.isPublic,onChange:g=>p("isPublic",!1)}),e.jsx("span",{className:"radio-mark"}),e.jsx("p",{children:"비공개"})]})]})})]}),e.jsx("div",{className:"form-row",children:e.jsxs("button",{type:"button",className:"advanced-toggle",onClick:()=>$(!T),children:["고급옵션 ",T?"닫기 -":"열기 +"]})}),T&&e.jsx("div",{className:"advanced-options",children:e.jsx("p",{children:"고급 옵션은 추후 추가 예정입니다."})})]})})]})]}),v==="stats"&&e.jsxs("div",{className:"stats-content",children:[e.jsxs("div",{className:"stats-header",children:[e.jsx("div",{className:"search-section",children:e.jsx("input",{type:"text",className:"search-box",placeholder:"search"})}),e.jsx("div",{className:"stats-actions",children:e.jsx("button",{className:"excel-export-btn",children:"엑셀파일로 변환하기"})})]}),e.jsx("div",{className:"stats-table-wrapper",children:e.jsxs("table",{className:"stats-table",children:[e.jsxs("colgroup",{children:[e.jsx("col",{}),e.jsx("col",{}),e.jsx("col",{}),e.jsx("col",{}),e.jsx("col",{}),e.jsx("col",{})]}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"학습자"}),e.jsx("th",{children:"전체 시간"}),e.jsx("th",{children:"학습 시간"}),e.jsx("th",{children:"출결 상태"}),e.jsx("th",{children:"학습 로그 정보"}),e.jsx("th",{children:"학습 완료 처리"})]})}),e.jsxs("tbody",{children:[e.jsxs("tr",{children:[e.jsxs("td",{children:["[email protected]",e.jsx("br",{}),"(테스트)"]}),e.jsx("td",{children:"30시간 35분 0초"}),e.jsx("td",{children:"0시간 0분 0초"}),e.jsx("td",{className:"incomplete",children:"미완료"}),e.jsx("td",{children:e.jsx("button",{className:"view-log-btn",children:"보기"})}),e.jsx("td",{children:e.jsx("button",{className:"manual-attendance-btn",children:"수동 출결 처리"})})]}),e.jsxs("tr",{children:[e.jsxs("td",{children:["[email protected]",e.jsx("br",{}),"(강성민)"]}),e.jsx("td",{children:"30시간 35분 0초"}),e.jsx("td",{children:"0시간 0분 0초"}),e.jsx("td",{className:"incomplete",children:"미완료"}),e.jsx("td",{children:e.jsx("button",{className:"view-log-btn",children:"보기"})}),e.jsx("td",{children:e.jsx("button",{className:"manual-attendance-btn",children:"수동 출결 처리"})})]})]})]})}),e.jsxs("div",{className:"pagination",children:[e.jsx("button",{type:"button",disabled:!0,children:"‹‹"}),e.jsx("button",{type:"button",disabled:!0,children:"‹"}),e.jsx("button",{type:"button",className:"active",disabled:!0,children:"1"}),e.jsx("button",{type:"button",disabled:!0,children:"›"}),e.jsx("button",{type:"button",disabled:!0,children:"››"})]})]})]}),e.jsxs("div",{className:"modal-footer",children:[e.jsx("button",{type:"submit",className:"btn-submit",form:"video-form",style:{display:v==="edit"?"block":"none"},children:"저장"}),e.jsx("button",{type:"button",onClick:k,className:"btn-cancel",children:"취소"})]}),F&&v==="edit"&&e.jsxs("div",{className:"pip-preview-overlay",children:[e.jsxs("div",{className:"pip-preview-header",children:[e.jsx("h4",{children:"학습자 화면 미리보기"}),e.jsx("button",{type:"button",className:"pip-close-btn",onClick:()=>A(!1),children:"×"})]}),e.jsx("div",{className:"pip-preview-content",children:e.jsxs("div",{className:"video-preview",children:[e.jsxs("div",{className:"player-wrapper",children:[e.jsx("div",{className:"player-layout",children:e.jsx("div",{className:"video-placeholder",children:i.videoType==="chunk"&&i.videoFile?e.jsx("div",{className:"video-info",children:e.jsxs("p",{children:["📹 업로드된 파일: ",i.videoFile.name]})}):i.videoType==="youtube"&&i.youtubeUrl?e.jsx("div",{className:"video-info",children:e.jsxs("p",{children:["📺 유튜브 URL: ",i.youtubeUrl]})}):e.jsxs("div",{className:"video-placeholder-content",children:[e.jsx("div",{className:"play-button",children:"▶"}),e.jsx("p",{children:"동영상이 여기에 표시됩니다"})]})})}),e.jsx("div",{className:"video-bottom",children:e.jsxs("div",{className:"video-info-wrap",children:[e.jsxs("div",{className:"video-infos",children:[e.jsxs("div",{children:["출석인정기간 : ",i.useAttendance?`${new Date(i.attendanceStart).toLocaleStr
2ing()} ~ ${new Date(i.attendanceEnd).toLocaleString()}`:"설정안됨"]}),e.jsxs("div",{children:["학습인정진도율: ",e.jsxs("strong",{children:[i.progress,"%"]})," 이상"]}),e.jsxs("div",{children:["공개여부: ",e.jsx("strong",{children:i.isPublic?"공개":"비공개"})]})]}),e.jsx("div",{className:"progress-zone-wrap",children:e.jsx("div",{className:"progress-zone",children:"0%"})})]})})]}),i.title&&e.jsx("div",{className:"video-title-preview",children:e.jsxs("h4",{children:["제목: ",i.title]})})]})})]})]})})})},Ti=({isOpen:n,onClose:l,onSuccess:h,cwUuid:d})=>{const[v,r]=t.useState(!1),[i,y]=t.useState([{id:1,title:"1주차 출석",date:"",start_time:"09:00",end_time:"12:00"}]),[T,$]=t.useState("instructor_managed"),[F,A]=t.useState(!1),[N,b]=t.useState(null),[k,w]=t.useState(10),[p,K]=t.useState(!1),[Z,Q]=t.useState(null),[g,B]=t.useState("manual"),[W,O]=t.useState({startDate:ji(),weeks:15,dayOfWeek:1,startTime:"09:00",endTime:"12:00"}),G=()=>{const C=[],o=new Date(W.startDate),z=o.getDay();let m=W.dayOfWeek-z;m<0&&(m+=7);const J=new Date(o);J.setDate(o.getDate()+m);for(let ve=0;ve<W.weeks;ve++){const xe=new Date(J);xe.setDate(J.getDate()+ve*7),C.push({id:ve+1,title:`${ve+1}주차 출석`,date:xe.toISOString().slice(0,10),start_time:W.startTime,end_time:W.endTime})}y(C)};if(t.useEffect(()=>{g==="weekly"&&W.startDate&&G()},[g,W]),t.useEffect(()=>{const C=o=>{o.key==="Escape"&&n&&l()};return n&&document.addEventListener("keydown",C),()=>{document.removeEventListener("keydown",C)}},[n,l]),!n)return null;const u=()=>{const C=Math.max(...i.map(o=>o.id),0)+1;y([...i,{id:C,title:`${C}주차 출석`,date:"",start_time:"09:00",end_time:"12:00"}])},q=C=>{i.length>1&&y(i.filter(o=>o.id!==C))},H=(C,o,z)=>{y(i.map(R=>R.id===C?{...R,[o]:z}:R))},Y=()=>{if(!navigator.geolocation){Q("브라우저에서 위치 서비스를 지원하지 않습니다.");return}K(!0),Q(null),navigator.geolocation.getCurrentPosition(async C=>{const{latitude:o,longitude:z}=C.coords;let R=`위도: ${o.toFixed(6)}, 경도: ${z.toFixed(6)}`;try{const m=await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${o}&lon=${z}&zoom=18&addressdetails=1`,{headers:{"Accept-Language":"ko"}});m.ok&&(R=(await m.json()).display_name||R)}catch(m){console.error("Failed to get address:",m)}b({latitude:o,longitude:z,address:R}),K(!1)},C=>{switch(K(!1),C.code){case C.PERMISSION_DENIED:Q("위치 권한이 거부되었습니다.");break;case C.POSITION_UNAVAILABLE:Q("위치 정보를 사용할 수 없습니다.");break;case C.TIMEOUT:Q("위치 요청 시간이 초과되었습니다.");break;default:Q("알 수 없는 오류가 발생했습니다.")}},{enableHighAccuracy:!0,timeout:1e4,maximumAge:0})},pe=async C=>{if(C.preventDefault(),i.filter(z=>!z.title.trim()||!z.date).length>0){alert("모든 세션의 제목과 날짜를 입력해주세요.");return}r(!0);try{const z={cw_uuid:d,sessions:i.map(m=>({title:m.title,date:m.date,start_time:m.start_time,end_time:m.end_time})),attendance_method:T};T==="student_checkin"&&F&&N&&(z.gps_location=N,z.gps_radius_meters=k);const R=await I.bulkCreateAttendanceBlocks(z);alert(`${R.created_count}개의 출석부가 생성되었습니다.`),h?.(),l()}catch(z){console.error("Failed to create attendance blocks:",z),alert(z.response?.data?.detail||"출석부 일괄 생성에 실패했습니다.")}finally{r(!1)}},ye=["일요일","월요일","화요일","수요일","목요일","금요일","토요일"];return e.jsx("div",{className:"activity-modal-overlay",onClick:l,children:e.jsxs("div",{className:"activity-modal-content large",onClick:C=>C.stopPropagation(),children:[e.jsxs("div",{className:"activity-modal-header",children:[e.jsx("h2",{children:"출석부 일괄 추가"}),e.jsx("button",{className:"close-btn",onClick:l,children:"×"})]}),e.jsxs("form",{onSubmit:pe,children:[e.jsxs("div",{className:"activity-modal-body",children:[e.jsxs("div",{className:"form-section",children:[e.jsx("h3",{children:"생성 방식"}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"radio-group horizontal",children:[e.jsxs("label",{className:"radio-label",children:[e.jsx("input",{type:"radio",name:"bulk_mode",value:"manual",checked:g==="manual",onChange:()=>B("manual")}),e.jsx("span",{children:"직접 입력"})]}),e.jsxs("label",{className:"radio-label",children:[e.jsx("input",{type:"radio",name:"bulk_mode",value:"weekly",checked:g==="weekly",onChange:()=>B("weekly")}),e.jsx("span",{children:"주차별 자동 생성"})]})]})}),g==="weekly"&&e.jsxs("div",{className:"weekly-config",children:[e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group half",children:[e.jsx("label",{children:"시작일"}),e.jsx("input",{type:"date",value:W.startDate,onChange:C=>O({...W,startDate:C.target.value}),className:"form-control"})]}),e.jsxs("div",{className:"form-group half",children:[e.jsx("label",{children:"총 주차"}),e.jsx("input",{type:"number",min:"1",max:"52",value:W.weeks,onChange:C=>O({...W,weeks:parseInt(C.target.value)||1}),className:"form-control"})]})]}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-group third",children:[e.jsx("label",{children:"수업 요일"}),e.jsx("select",{value:W.dayOfWeek,onChange:C=>O({...W,dayOfWeek:parseInt(C.target.value)}),className:"form-control",children:ye.map((C,o)=>e.jsx("option",{value:o,children:C},o))})]}),e.jsxs("div",{className:"form-group third",children:[e.jsx("label",{children:"시작 시간"}),e.jsx("input",{type:"time",value:W.startTime,onChange:C=>O({...W,startTime:C.target.value}),className:"form-control"})]}),e.jsxs("div",{className:"form-group third",children:[e.jsx("label",{children:"종료 시간"}),e.jsx("input",{type:"time",value:W.endTime,onChange:C=>O({...W,endTime:C.target.value}),className:"form-control"})]})]}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:G,children:"세션 생성"})]})]}),e.jsxs("div",{className:"form-section",children:[e.jsxs("h3",{children:["출석 세션 목록 (",i.length,"개)"]}),e.jsx("div",{className:"sessions-list",children:i.map((C,o)=>e.jsxs("div",{className:"session-entry",children:[e.jsx("div",{className:"session-number",children:o+1}),e.jsxs("div",{className:"session-fields",children:[e.jsx("input",{type:"text",value:C.title,onChange:z=>H(C.id,"title",z.target.value),placeholder:"출석부 제목",className:"form-control"}),e.jsx("input",{type:"date",value:C.date,onChange:z=>H(C.id,"date",z.target.value),className:"form-control"}),e.jsx("input",{type:"time",value:C.start_time,onChange:z=>H(C.id,"start_time",z.target.value),className:"form-control small"}),e.jsx("span",{className:"time-separator",children:"~"}),e.jsx("input",{type:"time",value:C.end_time,onChange:z=>H(C.id,"end_time",z.target.value),className:"form-control small"})]}),e.jsx("button",{type:"button",className:"btn btn-icon btn-danger",onClick:()=>q(C.id),disabled:i.length<=1,children:"×"})]},C.id))}),g==="manual"&&e.jsx("button",{type:"button",className:"btn btn-secondary add-session-btn",onClick:u,children:"+ 세션 추가"})]}),e.jsxs("div",{className:"form-section",children:[e.jsx("h3",{children:"출석 방식"}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"radio-group",children:[e.jsxs("label",{className:"radio-label",children:[e.jsx("input",{type:"radio",name:"attendance_method",value:"instructor_managed",checked:T==="instructor_managed",onChange:C=>$(C.target.value)}),e.jsxs("span",{className:"radio-text",children:[e.jsx("strong",{children:"교수자 관리"}),e.jsx("small",{children:"교수자/운영자가 직접 출석을 체크합니다."})]})]}),e.jsxs("label",{className:"radio-label",children:[e.jsx("input",{type:"radio",name:"attendance_method",value:"student_checkin",checked:T==="student_checkin",onChange:C=>$(C.target.value)}),e.jsxs("span",{className:"radio-text",children:[e.jsx("strong",{children:"학습자 직접 출석"}),e.jsx("small",{children:"학습자가 GPS 위치 확인 후 직접 출석합니다."})]})]})]})}),T==="student_checkin"&&e.jsxs("div",{className:"gps-settings",children:[e.jsx("div",{className:"form-group",children:e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:F,onChange:C=>A(C.target.checked)}),e.jsx("span",{children:"GPS 위치 확인 사용"})]})}),F&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"출석 인정 반경"}),e.jsxs("div",{className:"input-with-unit",children:[e.jsx("input",{type:"number",min:"1",max:"1000",value:k,onChange:C=>w(parseInt(C.target.value)),className:"form-control"}),e.jsx("span",{className:"unit",children:"미터"})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"출석 장소 위치"}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:Y,disabled:p,children:p?"위치 확인 중...":"현재 위치 가져ì˜
2¤ê¸°"}),Z&&e.jsx("div",{className:"error-message",children:Z}),N&&e.jsxs("div",{className:"location-info",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"위도:"})," ",N.latitude.toFixed(6)]}),e.jsxs("p",{children:[e.jsx("strong",{children:"경도:"})," ",N.longitude.toFixed(6)]}),e.jsxs("p",{children:[e.jsx("strong",{children:"주소:"})," ",N.address]})]})]})]})]})]})]}),e.jsxs("div",{className:"activity-modal-footer",children:[e.jsx("button",{type:"button",className:"btn btn-cancel",onClick:l,children:"취소"}),e.jsx("button",{type:"submit",className:"btn btn-primary",disabled:v,children:v?"생성 중...":`${i.length}개 출석부 생성`})]})]})]})})},Ei=({sessionTitle:n,moduleTitle:l,blockTitle:h,courseTitle:d,videoId:v,courseId:r,blockId:i})=>{const{t:y}=gs("lms"),[T,$]=t.useState([]),[F,A]=t.useState(""),[N,b]=t.useState(!1),[k,w]=t.useState(!1),[p,K]=t.useState(!1),Z=t.useRef(null),Q=()=>{if(Z.current){const O=Z.current.closest(".ai-tutor-messages");O&&(O.scrollTop=O.scrollHeight)}};t.useEffect(()=>{Q()},[T]),t.useEffect(()=>{(async()=>{if(!i){$([{role:"assistant",content:y("aiTutor.greeting","안녕하세요! AI 튜터입니다. 현재 학습 중인 내용에 대해 무엇이든 물어보세요. 😊")}]),K(!0);return}try{const G=await Ce.get("/ai-chat/history/video-tutor",{params:{block_id:i,limit:50}});if(G.data.messages&&G.data.messages.length>0){const u=G.data.messages.map(q=>({role:q.role,content:q.content}));u.length,$(u)}else $([{role:"assistant",content:y("aiTutor.greeting","안녕하세요! AI 튜터입니다. 현재 학습 중인 내용에 대해 무엇이든 물어보세요. 😊")}]);K(!0)}catch(G){console.error("[AI Tutor] Failed to load history:",G),$([{role:"assistant",content:y("aiTutor.greeting","안녕하세요! AI 튜터입니다. 현재 학습 중인 내용에 대해 무엇이든 물어보세요. 😊")}]),K(!0)}})()},[i,y]);const g=async O=>{const G={role:"user",content:O};$(u=>[...u,G,{role:"assistant",content:""}]),b(!0),w(!0);try{await li.chatStream({query:O,video_id:v,course_id:r,block_id:i,course_title:d,session_title:n,module_title:l,block_title:h},u=>{$(q=>{const H=[...q],Y=H.length-1;return Y>=0&&H[Y].role==="assistant"&&(H[Y]={...H[Y],content:H[Y].content+u}),H})},()=>{b(!1),w(!1)},u=>{console.error("[AI Tutor] Streaming error:",u),$(q=>{const H=[...q],Y=H.length-1;return Y>=0&&(H[Y]={role:"assistant",content:y("aiTutor.error","죄송합니다. 메시지 전송 중 오류가 발생했습니다. 다시 시도해 주세요.")}),H}),b(!1),w(!1)})}catch(u){console.error("[AI Tutor] Error:",u),$(q=>{const H=[...q],Y=H.length-1;return Y>=0&&(H[Y]={role:"assistant",content:y("aiTutor.error","죄송합니다. 메시지 전송 중 오류가 발생했습니다. 다시 시도해 주세요.")}),H}),b(!1),w(!1)}},B=async O=>{N||await g(O)},W=async O=>{if(O.preventDefault(),!F.trim()||N)return;const G=F.trim();A(""),await g(G)};return e.jsxs("div",{className:"ai-tutor-chat",children:[e.jsxs("div",{className:"ai-tutor-header",children:[e.jsx("div",{className:"ai-tutor-icon",children:e.jsx("img",{alt:y("aiTutor.title","AI 튜터"),src:"/images/chatbot.svg"})}),e.jsx("div",{className:"ai-tutor-title",children:y("aiTutor.title","AI 튜터")})]}),e.jsxs("div",{className:"ai-tutor-messages",children:[T.map((O,G)=>e.jsxs("div",{children:[e.jsxs("div",{className:`ai-tutor-message ${O.role==="user"?"user":"assistant"}`,children:[O.role==="assistant"&&e.jsx("div",{className:"message-avatar",children:e.jsx("img",{alt:y("aiTutor.title","AI 튜터"),src:"/images/chatbot.svg"})}),e.jsx("div",{className:"message-bubble",children:O.role==="assistant"?e.jsxs(e.Fragment,{children:[e.jsx(ri,{remarkPlugins:[bi],components:{a:({node:u,...q})=>e.jsx("a",{...q,target:"_blank",rel:"noopener noreferrer"})},children:O.content}),k&&G===T.length-1&&e.jsx("span",{className:"streaming-cursor",children:"▌"})]}):O.content})]}),G===0&&T.length===1&&!N&&e.jsxs("div",{className:"example-questions",children:[e.jsx("button",{onClick:()=>B(y("aiTutor.prompts.keyTerms","이 차시의 주요 용어를 설명해주세요")),className:"example-question-btn",children:y("aiTutor.quickActions.keyTerms","📚 주요 용어")}),e.jsx("button",{onClick:()=>B(y("aiTutor.prompts.basicConcepts","이 차시의 기본 개념을 100자 이내로 요약하고, 위키피디아 기반으로 관련된 개념 링크를 추가해주세요")),className:"example-question-btn",children:y("aiTutor.quickActions.basicConcepts","💡 핵심 내용")}),e.jsx("button",{onClick:()=>B(y("aiTutor.prompts.reviewQuiz","이 차시 내용에 대한 간단한 5지선다형 퀴즈를 1개만 출제해주세요")),className:"example-question-btn",children:y("aiTutor.quickActions.reviewQuiz","✏️ 확인 퀴즈")})]})]},G)),N&&!k&&e.jsxs("div",{className:"ai-tutor-message assistant",children:[e.jsx("div",{className:"message-avatar",children:e.jsx("img",{alt:y("aiTutor.title","AI 튜터"),src:"/images/chatbot.svg"})}),e.jsx("div",{className:"message-bubble loading",children:e.jsxs("div",{className:"typing-indicator",children:[e.jsx("span",{}),e.jsx("span",{}),e.jsx("span",{})]})})]}),e.jsx("div",{ref:Z})]}),e.jsxs("form",{className:"ai-tutor-input-form",onSubmit:W,children:[e.jsx("input",{type:"text",value:F,onChange:O=>A(O.target.value),placeholder:y("aiTutor.inputPlaceholder","질문을 입력하세요..."),className:"ai-tutor-input",disabled:N}),e.jsx("button",{type:"submit",className:"ai-tutor-send",disabled:N||!F.trim(),children:e.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",children:[e.jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})})]})]})},Li=({videoId:n,fileName:l,onOpenNewWindow:h,downloadUrl:d})=>{const[v,r]=t.useState(!0),[i,y]=t.useState(null),T=t.useRef(null),$=`/api/lms/notebook/html/${n}/${encodeURIComponent(l)}`,F=()=>{r(!1)},A=()=>{y("Notebook을 불러올 수 없습니다."),r(!1)},N=()=>{h?h():window.open($,"_blank")},b=()=>{if(d)window.open(d,"_blank");else{const w=`/api/lms/video/attachment/download/${n}/${encodeURIComponent(l)}`;window.open(w,"_blank")}},k=()=>{r(!0),y(null),T.current&&(T.current.src=$)};return e.jsxs("div",{className:"notebook-viewer-container",children:[e.jsxs("div",{className:"notebook-viewer-toolbar",children:[e.jsxs("div",{className:"toolbar-left",children:[e.jsx("span",{className:"notebook-icon",children:e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M4 19.5A2.5 2.5 0 0 1 6.5 17H20"}),e.jsx("path",{d:"M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"})]})}),e.jsx("span",{className:"notebook-filename",title:l,children:l})]}),e.jsxs("div",{className:"toolbar-right",children:[e.jsx("button",{className:"toolbar-btn",onClick:k,title:"새로고침",children:e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M23 4v6h-6"}),e.jsx("path",{d:"M1 20v-6h6"}),e.jsx("path",{d:"M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"})]})}),e.jsx("button",{className:"toolbar-btn",onClick:b,title:"다운로드 (.ipynb)",children:e.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:e.jsx("path",{d:"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"})})}),e.jsx("button",{className:"toolbar-btn",onClick:N,title:"새 창에서 열기",children:e.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:e.jsx("path",{d:"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3"})})})]})]}),e.jsxs("div",{className:"notebook-viewer-content",children:[v&&e.jsxs("div",{className:"notebook-loading",children:[e.jsx("div",{className:"loading-spinner"}),e.jsx("span",{children:"Notebook 불러오는 중..."})]}),i&&e.jsxs("div",{className:"notebook-error",children:[e.jsxs("svg",{width:"48",height:"48",viewBox:"0 0 24 24",fill:"none",stroke:"#dc2626",strokeWidth:"2",children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("line",{x1:"12",y1:"8",x2:"12",y2:"12"}),e.jsx("line",{x1:"12",y1:"16",x2:"12.01",y2:"16"})]}),e.jsx("span",{children:i}),e.jsx("button",{onClick:k,children:"다시 시도"})]}),e.jsx("iframe",{ref:T,src:$,className:"notebook-iframe",onLoad:F,onError:A,title:l,sandbox:"allow-scripts allow-same-origin",style:{display:v||i?"none":"block"}})]})]})},Pi=fs.lazy(()=>ci(()=>import("./HwpViewer-oqnOEjya.js"),__vite__mapDeps([0,1,2,3,4]))),Gn=n=>{const l=(n.file_name.split(".").pop()||"").toUpperCase();return l&&l.length<=5?l:n.file_type.toUpperCase()},Ri=({file:n,blockId:l,onClose:h})=>{const d=t.useRef(null),[v,r]=t.useState({x:20,y:20}),[i,y]=t.useState({width:480,height:640}),[T,$]=t.useState(!1),[F,A]=t.useState(!1),N=t.useRef({x:0,y:0}),b=t.useRef({x:0,y:0,width:0,height:0}),k=p=>{p.target.closest(".pip-close-btn")||p.target.closest(".pip-resize-handle")||($(!0),N.current={x:p.clientX-v.x,y:p.clientY-v.y})},w=p=>{p.stopPropagation(),A(!0),b.current={x:p.clientX,y:p.clientY,width:i.width,height:i.height}};return t.useEffect(()=>{const p=Z=>{if(T){const Q=Math.max(0,Math.min(window.innerWidth-i.width,Z.clientX-N.current.x)),g=Math.max(0,Math.min(window.innerHeight-i.height,Z.clientY-N.current.y));r({x:Q,y:g})}if(F){const Q=Z.clientX-b.current.x,g=Z.clientY-b.current.y,B=Math.max(320,Math.min(window.innerWidth-v.x,b.current.width+Q)),W=Math.max(400,Math.min(window.innerHeight-v.y,b.current.height+g));y({width:B,height:W})}},K=()=>{$(!1),A(!1)};return(T||F)&&(document.addEventListener("mousemove",p),document.addEventListener("mouseup",K)),()=>{document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",K)}},[T,F,v.x,v.y,i.width,i.height]),t.useEffect(()=>{const p=K=>{K.key==="Escape"&&h()};return document.addEventListener("keydown",p),()=>document.removeEventListener("keydown",p)}
2,[h]),tn.createPortal(e.jsxs("div",{ref:d,className:"pdf-pip-container",style:{left:v.x,top:v.y,width:i.width,height:i.height},children:[e.jsxs("div",{className:"pdf-pip-header",onMouseDown:k,children:[e.jsx("span",{className:"pip-title",title:n.file_name,children:n.file_name}),e.jsx("button",{className:"pip-close-btn",onClick:h,title:"닫기",children:e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),e.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),e.jsx("div",{className:"pdf-pip-content",children:e.jsx(aa,{url:n.file_path,blockId:l,fileName:n.file_name})}),e.jsx("div",{className:"pip-resize-handle",onMouseDown:w,children:e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"currentColor",children:e.jsx("path",{d:"M11 11H9V9H11V11ZM11 7H9V5H11V7ZM7 11H5V9H7V11ZM11 3H9V1H11V3ZM7 7H5V5H7V7ZM3 11H1V9H3V11Z",opacity:"0.5"})})})]}),document.body)},Kn=({attachments:n,blockId:l,videoId:h})=>{const[d,v]=t.useState(n.length>0?n[0]:null),[r,i]=t.useState(null);t.useEffect(()=>{r&&r.file_name},[r]);const y=b=>{b.file_name,i(b)},T=()=>{i(null)},$=b=>b<1024?`${b} B`:b<1024*1024?`${(b/1024).toFixed(1)} KB`:`${(b/(1024*1024)).toFixed(1)} MB`,F=b=>{switch(b){case"pdf":return e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"#dc2626",strokeWidth:"2",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"}),e.jsx("text",{x:"8",y:"17",fontSize:"6",fill:"#dc2626",stroke:"none",fontWeight:"bold",children:"PDF"})]});case"ipynb":return e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"#f97316",strokeWidth:"2",children:[e.jsx("path",{d:"M4 19.5A2.5 2.5 0 016.5 17H20"}),e.jsx("path",{d:"M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z"})]});case"office":return e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"#c2410c",strokeWidth:"2",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"}),e.jsx("line",{x1:"8",y1:"13",x2:"16",y2:"13"}),e.jsx("line",{x1:"8",y1:"17",x2:"13",y2:"17"})]});case"hwp":return e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"#0f766e",strokeWidth:"2",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"}),e.jsx("path",{d:"M8 13h2v4M8 15h4M12 13v4"})]});case"zip":return e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"#6366f1",strokeWidth:"2",children:[e.jsx("path",{d:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"}),e.jsx("polyline",{points:"3.27,6.96 12,12.01 20.73,6.96"}),e.jsx("line",{x1:"12",y1:"22.08",x2:"12",y2:"12"})]});default:return e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"#6b7280",strokeWidth:"2",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"})]})}},A=(b,k)=>{k&&(k.preventDefault(),k.stopPropagation());let w=b.file_path;w.includes("/attachment/")?w=w.replace("/attachment/","/attachment/download/"):w=w+(w.includes("?")?"&":"?")+"download=1";const p=document.createElement("a");p.href=w,p.download=b.file_name,p.target="_blank",document.body.appendChild(p),p.click(),document.body.removeChild(p)},N=b=>{if(b.file_name,b.file_type,b.file_type==="pdf")y(b);else if(b.file_type==="ipynb"){const k=`/api/lms/notebook/html/${h}/${encodeURIComponent(b.file_name)}`;window.open(k,"_blank")}else A(b)};return n.length===0?e.jsxs("div",{className:"materials-panel-empty",children:[e.jsxs("svg",{width:"48",height:"48",viewBox:"0 0 24 24",fill:"none",stroke:"#9ca3af",strokeWidth:"1.5",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"}),e.jsx("line",{x1:"16",y1:"13",x2:"8",y2:"13"}),e.jsx("line",{x1:"16",y1:"17",x2:"8",y2:"17"}),e.jsx("polyline",{points:"10,9 9,9 8,9"})]}),e.jsx("p",{children:"첨부된 참고자료가 없습니다."})]}):e.jsxs("div",{className:"materials-panel",children:[e.jsx("div",{className:"materials-file-list",style:n.length<=1?{display:"none"}:void 0,children:n.map(b=>e.jsxs("div",{className:`materials-file-item ${d?.file_id===b.file_id?"active":""}`,onClick:()=>v(b),children:[e.jsx("div",{className:"file-icon",children:F(b.file_type)}),e.jsxs("div",{className:"file-info",children:[e.jsx("span",{className:"file-name",title:b.file_name,children:b.file_name}),e.jsxs("span",{className:"file-meta",children:[b.file_size>0?`${$(b.file_size)} · `:"",Gn(b)]})]}),["zip","hwp","office"].includes(b.file_type)&&e.jsx("button",{className:"file-download-btn",onClick:k=>A(b,k),title:"다운로드",children:e.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:e.jsx("path",{d:"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"})})})]},b.file_id))}),e.jsxs("div",{className:"materials-viewer",children:[d?.file_type==="pdf"&&e.jsx(aa,{url:d.file_path,blockId:l,fileName:d.file_name,onOpenNewWindow:()=>N(d)}),d?.file_type==="ipynb"&&e.jsx(Li,{videoId:h,fileName:d.file_name,onOpenNewWindow:()=>N(d),downloadUrl:d.file_path.replace("/attachment/","/attachment/download/")}),d?.file_type==="office"&&(()=>{const b=yi(d.file_path);return b?e.jsx(_i,{docId:b,fileName:d.file_name,mode:"view"}):e.jsxs("div",{className:"materials-zip-prompt",children:[e.jsx("h3",{children:"미리보기를 열 수 없습니다"}),e.jsx("p",{children:d.file_name}),e.jsx("button",{className:"zip-download-btn",onClick:k=>A(d,k),children:"다운로드"})]})})(),d?.file_type==="hwp"&&e.jsx(fs.Suspense,{fallback:e.jsx("div",{className:"materials-hwp-loading",children:"문서 엔진을 준비하는 중..."}),children:e.jsx(Pi,{url:d.file_path,fileName:d.file_name,mode:"view",editable:!1})}),d?.file_type==="zip"&&e.jsxs("div",{className:"materials-zip-prompt",children:[e.jsxs("svg",{width:"64",height:"64",viewBox:"0 0 24 24",fill:"none",stroke:"#6366f1",strokeWidth:"1.5",children:[e.jsx("path",{d:"M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"}),e.jsx("polyline",{points:"3.27,6.96 12,12.01 20.73,6.96"}),e.jsx("line",{x1:"12",y1:"22.08",x2:"12",y2:"12"})]}),e.jsxs("h3",{children:[Gn(d)," 파일"]}),e.jsx("p",{children:d.file_name}),d.file_size>0&&e.jsx("p",{className:"zip-size",children:$(d.file_size)}),e.jsx("p",{className:"zip-size",children:"이 형식은 미리보기가 없습니다. 내려받아 여세요."}),e.jsxs("button",{className:"zip-download-btn",onClick:b=>A(d,b),children:[e.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:e.jsx("path",{d:"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"})}),"다운로드"]})]}),!d&&n.length>0&&e.jsx("div",{className:"materials-select-prompt",children:e.jsx("p",{children:"왼쪽에서 파일ì
2„ 선택하세요."})})]}),r&&r.file_type==="pdf"&&e.jsx(Ri,{file:r,blockId:l,onClose:T})]})},Zs={PRESENT:{label:"출석",bg:"#dcfce7",fg:"#15803d"},LATE:{label:"지각",bg:"#fef3c7",fg:"#b45309"},EXCUSED:{label:"공결",bg:"#e5e7eb",fg:"#4b5563"},ABSENT:{label:"결석",bg:"#fee2e2",fg:"#b91c1c"},"":{label:"미입장",bg:"#f3f4f6",fg:"#9ca3af"}},Mi=["PRESENT","LATE","EXCUSED","ABSENT"],Ai=3e4,$i=n=>{const l=Lt(n);return l?l.toLocaleString("ko-KR",{timeZone:"Asia/Seoul"}):"-"},zi=({blockId:n,cwUuid:l,cohortId:h})=>{const[d,v]=t.useState(null),[r,i]=t.useState(!0),[y,T]=t.useState(null),[$,F]=t.useState(null),A=t.useCallback(async(w=!1)=>{w||(i(!0),T(null));try{const p=await I.getLiveRoster(n,l,h);v(p),T(null)}catch(p){w||T(p?.response?.data?.detail||"출석 명단을 불러오지 못했습니다.")}finally{w||i(!1)}},[n,l,h]);t.useEffect(()=>{A()},[A]),t.useEffect(()=>{const w=setInterval(()=>{A(!0)},Ai);return()=>clearInterval(w)},[A]);const N=async(w,p)=>{F(w+p);try{await I.markLiveAttendance(n,{cw_uuid:l,...h?{cohort_id:h}:{},grade_user_id:w,status:p}),await A()}catch(K){alert(K?.response?.data?.detail||"출석 보정에 실패했습니다.")}finally{F(null)}},b={border:"1px solid #e5e7eb",borderRadius:"10px",padding:"16px",marginBottom:"16px",background:"#fff"};if(r)return e.jsx("div",{style:b,children:"출석 명단을 불러오는 중..."});if(y)return e.jsxs("div",{style:b,children:[e.jsx("span",{style:{color:"#b91c1c"},children:y})," ",e.jsx("button",{onClick:()=>A(),style:{textDecoration:"underline"},children:"다시 시도"})]});if(!d)return null;const k=w=>{const p=Zs[w]||Zs[""];return e.jsx("span",{style:{background:p.bg,color:p.fg,borderRadius:"999px",padding:"2px 10px",fontSize:"12px",fontWeight:600},children:p.label})};return e.jsxs("div",{style:b,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"12px",flexWrap:"wrap",marginBottom:"12px"},children:[e.jsx("h4",{style:{fontWeight:700,margin:0},children:"학습현황 및 평가 · 출석 명단"}),e.jsxs("span",{style:{fontSize:"13px",color:"#4b5563"},children:["입장 ",e.jsx("b",{style:{color:"#4338ca"},children:d.entered})," · ","출석 ",e.jsx("b",{style:{color:"#15803d"},children:d.present})," / 전체 ",d.total]}),e.jsx("button",{onClick:()=>A(),style:{marginLeft:"auto",fontSize:"13px",color:"#4338ca",textDecoration:"underline"},children:"새로고침"})]}),d.roster.length===0?e.jsx("p",{style:{color:"#9ca3af",fontSize:"14px"},children:"수강생이 없습니다."}):e.jsx("div",{style:{overflowX:"auto"},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"14px"},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{textAlign:"left",color:"#6b7280",borderBottom:"1px solid #e5e7eb"},children:[e.jsx("th",{style:{padding:"8px 6px"},children:"이름"}),e.jsx("th",{style:{padding:"8px 6px"},children:"상태"}),d.tracks_progress&&e.jsx("th",{style:{padding:"8px 6px"},children:"시청"}),e.jsx("th",{style:{padding:"8px 6px"},children:"입장 시각"}),e.jsx("th",{style:{padding:"8px 6px"},children:"수동 보정"})]})}),e.jsx("tbody",{children:d.roster.map(w=>e.jsxs("tr",{style:{borderBottom:"1px solid #f3f4f6"},children:[e.jsxs("td",{style:{padding:"8px 6px"},children:[e.jsx("div",{style:{fontWeight:600},children:w.name}),w.email&&e.jsx("div",{style:{fontSize:"12px",color:"#9ca3af"},children:w.email})]}),e.jsx("td",{style:{padding:"8px 6px"},children:k(w.status)}),d.tracks_progress&&e.jsxs("td",{style:{padding:"8px 6px",color:"#4b5563",fontVariantNumeric:"tabular-nums"},children:[w.progress_percent,"%"]}),e.jsx("td",{style:{padding:"8px 6px",color:"#4b5563",fontVariantNumeric:"tabular-nums"},children:$i(w.checked_in_at)}),e.jsx("td",{style:{padding:"8px 6px"},children:e.jsx("div",{style:{display:"flex",gap:"4px",flexWrap:"wrap"},children:Mi.map(p=>{const K=Zs[p],Z=w.status===p;return e.jsx("button",{onClick:()=>N(w.grade_user_id,p),disabled:$===w.grade_user_id+p,title:`${K.label}(으)로 표시`,style:{border:`1px solid ${Z?K.fg:"#d1d5db"}`,background:Z?K.bg:"#fff",color:Z?K.fg:"#6b7280",borderRadius:"6px",padding:"2px 8px",fontSize:"12px",fontWeight:Z?700:500,cursor:"pointer"},children:K.label},p)})})})]}
2,w.grade_user_id))})]})})]})},Di=5e3,Qn=1e3,Xn=15e3;function la(){if(typeof window>"u")return{ok:!1,reason:"브라우저 환경이 아닙니다."};if(!navigator.mediaDevices?.getDisplayMedia)return{ok:!1,reason:"이 브라우저는 화면 공유를 지원하지 않습니다. Chrome 또는 Edge 를 사용해주세요."};if(typeof MediaRecorder>"u")return{ok:!1,reason:"이 브라우저는 화면 녹화를 지원하지 않습니다. Chrome 또는 Edge 를 사용해주세요."};const l=["video/webm;codecs=vp9,opus","video/webm;codecs=vp8,opus","video/webm"].find(h=>MediaRecorder.isTypeSupported(h));return l?window.isSecureContext?{ok:!0,mimeType:l}:{ok:!1,reason:"HTTPS 에서만 녹화할 수 있습니다."}:{ok:!1,reason:"이 브라우저가 지원하는 녹화 형식이 없습니다. Chrome 또는 Edge 를 사용해주세요."}}function Ii(){const[n,l]=t.useState({state:"idle",elapsedSec:0,chunksMade:0,chunksSent:0,pendingUpload:0,bytesMade:0,localSaving:!1,localFileName:null,error:null,warning:null,recordingId:null}),h=t.useRef(null),d=t.useRef([]),v=t.useRef(null),r=t.useRef(null),i=t.useRef(0),y=t.useRef(0),T=t.useRef(0),$=t.useRef(null),F=t.useRef(null),A=t.useRef([]),N=t.useRef(!1),b=t.useRef(!1),k=t.useCallback(g=>{l(B=>({...B,...g}))},[]),w=t.useCallback(async()=>{if(N.current)return;N.current=!0;let g=Qn;try{for(;A.current.length>0;){const B=F.current;if(!B)break;const W=A.current[0];try{const O=new FormData;O.append("file",W.blob,`chunk_${W.seq}`),O.append("cw_uuid",B.cwUuid),O.append("seq",String(W.seq));const G=await fetch(`/api/lms/live-recording/chunk/${B.recordingId}`,{method:"POST",body:O,credentials:"include"});if(!G.ok)throw new Error(`HTTP ${G.status}`);A.current.shift(),y.current+=1,g=Qn,k({chunksSent:y.current,pendingUpload:A.current.length})}catch{if(b.current&&g>=Xn)break;k({pendingUpload:A.current.length,warning:"서버 전송이 지연되고 있습니다. 녹화는 계속되며 로컬 파일에 저장됩니다."}),await new Promise(O=>setTimeout(O,g)),g=Math.min(g*2,Xn)}}A.current.length===0&&k({warning:null})}finally{N.current=!1}},[k]),p=t.useCallback(()=>{$.current&&(clearInterval($.current),$.current=null),d.current.forEach(g=>g.getTracks().forEach(B=>{try{B.stop()}catch{}})),d.current=[];try{v.current?.close()}catch{}v.current=null,h.current=null},[]),K=t.useCallback(async g=>{const B=la();if(!B.ok){k({state:"error",error:B.reason||"녹화를 지원하지 않습니다."});return}k({state:"preparing",error:null,warning:null}),i.current=0,y.current=0,A.current=[],b.current=!1;let W;try{W=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:20},audio:!0})}catch(o){k({state:"idle",error:o?.name==="NotAllowedError"?"화면 공유가 취소되었습니다.":o?.message||"화면 공유를 시작할 수 없습니다."});return}d.current.push(W);let O=null;try{O=await navigator.mediaDevices.getUserMedia({audio:!0}),d.current.push(O)}catch{k({warning:"마이크를 사용할 수 없어 화면 소리만 녹음됩니다."})}const G=[...W.getVideoTracks()],u=W.getAudioTracks(),q=O?.getAudioTracks()||[];
2if(u.length&&q.length){const o=new AudioContext;v.current=o;const z=o.createMediaStreamDestination();o.createMediaStreamSource(new MediaStream(u)).connect(z),o.createMediaStreamSource(new MediaStream(q)).connect(z),G.push(...z.stream.getAudioTracks())}else G.push(...u,...q),u.length||k({warning:'화면 소리가 공유되지 않았습니다. 다시 시작할 때 "탭 오디오 공유"를 켜주세요.'});const H=new MediaStream(G);let Y=null;const pe=`${(g.title||"실시간수업").replace(/[\\/:*?"<>|]/g,"_")}_${Vt(new Date).replace(/[-: ]/g,"")}.webm`;if(window.showSaveFilePicker)try{const o=await window.showSaveFilePicker({suggestedName:pe,types:[{description:"WebM 동영상",accept:{"video/webm":[".webm"]}}]});r.current=await o.createWritable(),Y=o.name||pe}catch{r.current=null,k({warning:"로컬 저장을 건너뜁니다(서버 전송만 진행). 종료 후 서버 녹화를 확인해주세요."})}else k({warning:"이 브라우저는 로컬 동시 저장을 지원하지 않습니다(서버 전송만 진행)."});let ye;try{ye=await I.liveRecStart(g.blockId,{cw_uuid:g.cwUuid,...g.cohortId?{cohort_id:g.cohortId}:{},...g.title?{title:g.title}:{},...Y?{local_file_name:Y}:{}})}catch(o){p();try{await r.current?.close()}catch{}r.current=null,k({state:"error",error:o?.response?.data?.detail||"녹화를 시작할 수 없습니다."});return}F.current={recordingId:ye.recording_id,cwUuid:g.cwUuid};const C=new MediaRecorder(H,{mimeType:B.mimeType,videoBitsPerSecond:15e5});h.current=C,C.ondataavailable=o=>{if(!o.data||!o.data.size)return;const z=i.current++;l(R=>({...R,chunksMade:z+1,bytesMade:R.bytesMade+o.data.size})),r.current&&r.current.write(o.data).catch(()=>{r.current=null,k({localSaving:!1,warning:"로컬 저장이 중단되었습니다(서버 전송은 계속됩니다)."})}),A.current.push({seq:z,blob:o.data}),k({pendingUpload:A.current.length}),w()},W.getVideoTracks()[0]?.addEventListener("ended",()=>{if(h.current?.state==="recording")try{h.current.stop()}catch{}}),T.current=Date.now(),$.current=setInterval(()=>{k({elapsedSec:Math.floor((Date.now()-T.current)/1e3)})},1e3),C.start(Di),k({state:"recording",recordingId:ye.recording_id,localSaving:!!r.current,localFileName:Y,chunksMade:0,chunksSent:0,bytesMade:0,elapsedSec:0})},[k,w,p]),Z=t.useCallback(async g=>{const B=h.current,W=F.current;k({state:"stopping"}),b.current=!0,await new Promise(G=>{if(!B||B.state==="inactive")return G();B.addEventListener("stop",()=>G(),{once:!0});try{B.stop()}catch{G()}setTimeout(G,4e3)});const O=Math.max(1,Math.floor((Date.now()-T.current)/1e3));p();try{await r.current?.close()}catch{}if(r.current=null,k({state:"finalizing"}),await w(),!W)return k({state:"idle"}),null;try{const G=await I.liveRecStop(W.recordingId,{cw_uuid:W.cwUuid,duration_sec:O,total_chunks:i.current,aborted:!!g?.aborted});return k({state:"done",pendingUpload:A.current.length}),G}catch(G){return k({state:"error",error:G?.response?.data?.detail||"녹화 저장을 마무리하지 못했습니다. 로컬 파일이 있으면 복구할 수 있습니다."}),null}},[k,w,p]);t.useEffect(()=>{if(n.state!=="recording")return;const g=B=>(B.preventDefault(),B.returnValue="","");return window.addEventListener("beforeunload",g),()=>window.removeEventListener("beforeunload",g)},[n.state]),t.useEffect(()=>()=>{p()},[p]);const Q=t.useCallback(()=>{l({state:"idle",elapsedSec:0,chunksMade:0,chunksSent:0,pendingUpload:0,bytesMade:0,localSaving:!1,localFileName:null,error:null,warning:null,recordingId:null}),F.current=null,A.current=[]},[]);return{status:n,start:K,stop:Z,reset:Q}}const Bi=n=>{const l=Math.floor(n/3600),h=Math.floor(n%3600/60),d=n%60;return(l>0?`${l}:`:"")+`${String(h).padStart(2,"0")}:${String(d).padStart(2,"0")}`},Wi=n=>n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(0)} KB`:n<1024*1024*1024?`${(n/1024/1024).toFixed(1)} MB`:`${(n/1024/1024/1024).toFixed(2)} GB`,Fi=({blockId:n,cwUuid:l,cohortId:h,defaultTitle:d,variant:v="standalone",onFinished:r})=>{const{status:i,start:y,stop:T,reset:$}=Ii(),[F,A]=t.useState(d||""),N=la(),b=i.state==="preparing"||i.state==="stopping"||i.state==="finalizing",k=v==="client";if(!N.ok)return e.jsxs("div",{className:`live-rec live-rec--unsupported ${k?"live-rec--compact":""}`,children:[e.jsx("b",{children:"이 브라우저에서는 클라이언트 녹화를 할 수 없습니다."}),e.jsx("p",{children:N.reason})]});const w=async(p=!1)=>{await T({aborted:p})&&!p&&r?.()};return e.jsxs("div",{className:`live-rec ${k?"live-rec--compact":""}`,children:[e.jsxs("div",{className:"live-rec__head",children:[e.jsx("span",{className:`live-rec__dot ${i.state==="recording"?"on":""}`}),e.jsx("b",{children:k?"2. 클라이언트 녹화 (자체)":"수업 녹화"}),i.state==="recording"&&e.jsx("span",{className:"live-rec__time",children:Bi(i.elapsedSec)})]}),i.state==="idle"&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"live-rec__guide",children:["이 브라우저가 화면공유로 녹화합니다. 공유 선택창에서 ",e.jsx("b",{children:'"이 탭"'})," 을 고르고"," ",e.jsx("b",{children:'"탭 오디오도 공유"'})," 를 켜주세요 — 그래야 참가자 음성이 함께 녹음됩니다. (교수자 마이크는 자동으로 같이 녹음됩니다)",k&&e.jsxs(e.Fragment,{children:[" 녹화 중에는 ",e.jsx("b",{children:"이 탭을 닫지 마세요."})]})]}),!k&&e.jsx("input",{className:"live-rec__title",placeholder:"녹화 제목 (비우면 자동 생성)",value:F,onChange:p=>A(p.target.value)}),e.jsx("button",{className:"live-rec__btn live-rec__btn--start",onClick:()=>y({blockId:n,cwUuid:l,cohortId:h,title:F.trim()||void 0}),children:"클라이언트 녹화 시작"})]}),(i.state==="recording"||b)&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"live-rec__stats",children:[e.jsxs("span",{children:["조각 ",i.chunksMade,"개 · ",Wi(i.bytesMade)]}),e.jsxs("span",{children:["서버 전송 ",i.chunksSent,"/",i.chunksMade,i.pendingUpload>0&&e.jsxs("b",{className:"live-rec__pending",children:[" (대기 ",i.pendingUpload,")"]})]}),e.jsx("span",{className:i.localSaving?"ok":"warn",children:i.localSaving?`로컬 저장 중: ${i.localFileName}`:"로컬 저장 안 함"})]}),i.state==="recording"&&e.jsxs("div",{className:"live-rec__actions",children:[e.jsx("button",{className:"live-rec__btn live-rec__btn--stop",onClick:()=>w(!1),children:"녹화 종료 · 저장"}),e.jsx("button",{className:"live-rec__btn live-rec__btn--ghost",onClick:()=>{window.confirm("녹화를 취소하면 서버에 저장하지 않습니다. 계속할까요?")&&w(!0)},children:"취소"})]}),b&&e.jsxs("p",{className:"live-rec__busy",children:[i.state==="preparing"&&"화면 공유를 준비하고 있습니다...",i.state==="stopping"&&"녹화를 마무리하고 있습니다...",i.state==="finalizing"&&`남은 조각을 전송하고 있습니다... (${i.pendingUpload}개)`]})]}),i.state==="done"&&e.jsxs("div",{className:"live-rec__done",children:[e.jsx("b",{children:"녹화가 저장되었습니다."}
2),e.jsxs("p",{children:["인코딩이 끝나면 아래 목록에서 재생할 수 있습니다(영상 길이에 따라 수 분 소요).",i.localFileName&&e.jsxs(e.Fragment,{children:[" 로컬 파일도 저장되었습니다: ",e.jsx("code",{children:i.localFileName})]})]}),e.jsx("button",{className:"live-rec__btn live-rec__btn--ghost",onClick:$,children:"새 녹화 준비"})]}),i.state==="error"&&e.jsxs("div",{className:"live-rec__error",children:[e.jsx("b",{children:i.error}),i.localFileName&&e.jsxs("p",{children:["로컬 파일 ",e.jsx("code",{children:i.localFileName})," 이 남아 있습니다. 동영상 업로드로 직접 올릴 수 있습니다."]}),e.jsx("button",{className:"live-rec__btn live-rec__btn--ghost",onClick:$,children:"다시 시도"})]}),i.warning&&i.state!=="error"&&e.jsx("p",{className:"live-rec__warn",children:i.warning})]})},Zn=20,qi=25,Oi=60,Hi=["microphone","camera","desktop","fullscreen","hangup","chat","raisehand","reactions","participants-pane","polls","tileview","settings","videoquality","toggle-camera","select-background","noisesuppression","shortcuts","help"],Ot={};function Vi(n){return window.JitsiMeetExternalAPI?Promise.resolve():(Ot[n]||(Ot[n]=new Promise((l,h)=>{const d=document.createElement("script");d.src=`https://${n}/external_api.js`,d.async=!0,d.onload=()=>l(),d.onerror=()=>{delete Ot[n],h(new Error("external_api.js 로드 실패"))},document.body.appendChild(d)})),Ot[n])}const Gi=({domain:n,roomId:l,displayName:h,email:d,isHost:v,jwt:r,blockId:i,cwUuid:y,cohortId:T,trackProgress:$=!0,onProgress:F,onClose:A,onRecordingChange:N,recTitle:b,onClientRecorded:k,endHandleRef:w})=>{const p=t.useRef(null),K=t.useRef(null),Z=t.useRef(!1),[Q,g]=t.useState(null),[B,W]=t.useState(!1),O=t.useRef(A);O.current=A;const G=t.useRef(N);G.current=N;const u=t.useRef(k);u.current=k;const[q,H]=t.useState(!1),[Y,pe]=t.useState(!1),[ye,C]=t.useState(null),o=t.useRef(!1),[z,R]=t.useState(!1),[m,J]=t.useState(null),ve=t.useRef(!1),xe=t.useRef(!1);if(xe.current=z,t.useEffect(()=>{let oe=!1,ee=null,de=null,Te=null;const Ze=async()=>{if(!Z.current&&!(typeof document<"u"&&document.visibilityState!=="visible"))try{const ue=await I.liveHeartbeat(i,{cw_uuid:y,...T?{cohort_id:T}:{},played_sec:Zn});F?.(ue.progress_percent,ue.achieve)}catch{}};return Vi(n).then(()=>{if(oe||!p.current||!window.JitsiMeetExternalAPI)return;const ue=new window.JitsiMeetExternalAPI(n,{roomName:l,parentNode:p.current,width:"100%",height:"100%",...r?{jwt:r}:{},userInfo:{displayName:h||"",...d?{email:d}:{}},configOverwrite:{prejoinPageEnabled:!1,prejoinConfig:{enabled:!1},requireDisplayName:!1,disableDeepLinking:!0,disableInviteFunctions:!0,doNotStoreRoom:!0,...v?{}:{localRecording:{disable:!0}}},interfaceConfigOverwrite:{MOBILE_APP_PROMO:!1,SHOW_JITSI_WATERMARK:!1,SHOW_BRAND_WATERMARK:!1,HIDE_INVITE_MORE_HEADER:!0,DISABLE_JOIN_LEAVE_NOTIFICATIONS:!0,DISPLAY_WELCOME_PAGE_CONTENT:!1,...v?{}:{TOOLBAR_BUTTONS:Hi}}});K.current=ue,w&&(w.current=async()=>{try{v&&ue.executeCommand("endConference")}catch{}try{ue.executeCommand("hangup")}catch{}await new Promise(Pe=>window.setTimeout(Pe,700))});const $e=()=>{if(h)try{ue.executeCommand("displayName",h)}catch{}};$e();const Oe=()=>{oe||(Z.current=!0,W(!1),v&&!ve.current&&(ve.current=!0,I.jibriPing(i,{cw_uuid:y,on:!1,recorded:xe.current}).catch(()=>{}),I.liveHostSignal(i,{cw_uuid:y,cohort_id:T,on:!1}).catch(()=>{})),O.current?.())};ue.addEventListener("videoConferenceJoined",()=>{Z.current=!1,de&&(clearTimeout(de),de=null),W(!0),$e(),v&&Ge(),v&&I.liveHostSignal(i,{cw_uuid:y,cohort_id:T,on:!0}).catch(()=>{})}),ue.addEventListener("videoConferenceLeft",()=>{Z.current=!0,W(!1),de&&clearTimeout(de),de=setTimeout(()=>{Z.current&&Oe()},3e3)}),ue.addEventListener("readyToClose",()=>{de&&(clearTimeout(de),de=null),Oe()}),ue.addEventListener("participantRoleChanged",Pe=>{v&&Pe?.role==="moderator"&&Ge()});let Ve=!1;ue.addEventListener("recordingStatusChanged",Pe=>{if(oe)return;const me=!!Pe?.on;Ve=me,me&&(o.current=!0,R(!0)),pe(!1),H(me),Pe?.error?C(String(Pe.error)):me&&C(null),G.current?.(me)});const Ge=async()=>
2{if(oe||!v||o.current)return;o.current=!0;try{const Re=await I.jibriPing(i,{cw_uuid:y,on:!0});if(oe)return;J({active:Re.active,limit:Re.limit,jibri_available:!0})}catch(Re){if(oe)return;J({active:Re?.response?.data?.active??10,limit:10,jibri_available:!1}),C(Re?.response?.data?.detail||"서버 녹화 정원이 찼습니다. 아래 클라이언트 녹화를 사용해주세요.");return}pe(!0);const Pe=()=>{try{ue.executeCommand("startRecording",{mode:"file"})}catch{}};Pe();let me=0;Te=window.setInterval(()=>{if(me+=1,oe||Ve||me>qi){window.clearInterval(Te),Te=null,!oe&&!Ve&&(pe(!1),C("녹화를 시작하지 못했습니다. 위 버튼으로 다시 시도하거나 클라이언트 녹화를 사용해주세요."));return}Pe()},1e3)};$&&(ee=setInterval(Ze,Zn*1e3))}).catch(ue=>{oe||g(ue?.message||"화상수업을 불러오지 못했습니다.")}),()=>{oe=!0,ee&&clearInterval(ee),de&&clearTimeout(de),Te&&(clearTimeout(Te),clearInterval(Te));try{v&&K.current?.executeCommand("endConference")}catch{}try{K.current?.executeCommand("hangup")}catch{}try{K.current?.dispose()}catch{}K.current=null,w&&(w.current=null),Z.current=!1}},[n,l,i,y,T,h,d,v,r,$]),t.useEffect(()=>{if(!v||!q)return;let oe=!0;const ee=()=>{I.jibriPing(i,{cw_uuid:y,on:!0}).then(Te=>{oe&&J({active:Te.active,limit:Te.limit,jibri_available:!0})}).catch(()=>{})};ee();const de=window.setInterval(ee,6e4);return()=>{oe=!1,window.clearInterval(de)}},[v,q,i,y]),t.useEffect(()=>{if(v)return ve.current=!1,()=>{ve.current||(ve.current=!0,I.jibriPing(i,{cw_uuid:y,on:!1,recorded:xe.current}).catch(()=>{}))}},[v,i,y]),t.useEffect(()=>{if(!v||!B)return;let oe=!0;const ee=()=>{I.liveHostSignal(i,{cw_uuid:y,cohort_id:T,on:!0}).catch(()=>{})};ee();const de=window.setInterval(()=>{oe&&ee()},Oi*1e3);return()=>{oe=!1,window.clearInterval(de)}},[v,B,i,y,T]),t.useEffect(()=>{if(!v||!B)return;let oe=!0;return I.getRecordingCapacity(y).then(ee=>{oe&&J(de=>de??ee)}).catch(()=>{}),()=>{oe=!1}},[v,B,y]),Q)return e.jsxs("div",{style:{padding:"24px",borderRadius:"10px",background:"#111",color:"#eee",textAlign:"center"},children:[Q,e.jsx("div",{style:{marginTop:"10px",fontSize:"13px",color:"#9ca3af"},children:"잠시 후 다시 시도하거나 관리자에게 문의해주세요."})]});const Ie=async()=>{const oe=K.current;if(oe){if(o.current=!0,C(null),q){pe(!0);try{oe.executeCommand("stopRecording","file")}catch(ee){pe(!1),C(ee?.message||"녹화 중지에 실패했습니다.")}window.setTimeout(()=>pe(!1),12e3);return}pe(!0);try{const ee=await I.jibriPing(i,{cw_uuid:y,on:!0});J({active:ee.active,limit:ee.limit,jibri_available:!0})}catch(ee){pe(!1),J({active:ee?.response?.data?.active??10,limit:10,jibri_available:!1}),C(ee?.response?.data?.detail||"서버 녹화 정원이 찼습니다. 클라이언트 녹화를 사용해주세요.");return}try{oe.executeCommand("startRecording",{mode:"file"})}catch(ee){pe(!1),C(ee?.message||"녹화 명령을 보내지 못했습니다.")}window.setTimeout(()=>pe(!1),12e3)}};return e.jsxs("div",{children:[e.jsx("div",{ref:p,style:{width:"100%",height:"68vh",borderRadius:"10px",overflow:"hidden",background:"#000"}}),!B&&e.jsxs("p",{style:{fontSize:"12px",color:"#9ca3af",marginTop:"6px"},children:["화상수업에 연결 중입니다",h?` — ${h}`:"","..."]}),v&&B&&e.jsxs("div",{className:"live-jibri",children:[e.jsxs("div",{className:"live-jibri__row",children:[e.jsx("span",{className:`live-jibri__dot ${q?"on":""}`}),e.jsx("b",{className:"live-jibri__label",children:q?"서버 녹화 중":"수업 녹화"}),m&&e.jsxs("span",{className:`live-jibri__cap ${m.jibri_available?"":"full"}`,children:["서버 녹화 ",m.active,"/",m.limit]}),e.jsx("button",{className:`live-jibri__btn ${q?"live-jibri__btn--stop":""}`,onClick:Ie,disabled:Y||(!q&&m?!m.jibri_available:!1),title:!q&&m&&!m.jibri_available?`서버 녹화가 정원(${m.limit}개)까지 진행 중입니다`:"서버(Jibri)가 회의를 녹화합니다",children:Y?"처리 중...":q?"서버 녹화 종료":"1. 서버 녹화 (Jibri)"})]}),e.jsx("span",{className:"live-jibri__hint",children:ye||(q?"서버에서 녹화 중입니다. 이 창을 닫아도 계속 녹화됩니다.":Y?"녹화를 시작하고 있습니다...":m&&!m.jibri_available?`서버 녹화가 정원(${m.limit}개)까지 진행 중입니다. 아래 클라이언트 녹화를 사용해주세요.`:z?"녹화가 꺼져 있습니다. 필요하면 다시 시작할 수 있습니다.":"녹화가 꺼져 있습니다.")}),!q&&e.jsx("div",{className:"live-jibri__client",children:e.jsx(Fi,{blockId:i,cwUuid:y,cohortId:T,defaultTitle:b,variant:"client",onFinished:u.current})})]})]})},Ki=n=>{if(!n)return"-";const l=Math.floor(n/3600),h=Math.floor(n%3600/60),d=n%60;return l>0?`${l}시간 ${h}분`:h>0?`${h}분 ${d}초`:`${d}초`},Qi=n=>n?new Date(n.endsWith("Z")?n:`${n}
2Z`).toLocaleString("ko-KR",{dateStyle:"medium",timeStyle:"short"}):"",Xi={absent:"미출석자만 (보충학습)",all:"전체 공개 (복습 허용)",none:"비공개"},Zi=20,Yi=({rec:n,cwUuid:l,cohortId:h,canManage:d,onGranted:v})=>{const r=t.useRef(null),i=t.useRef(null),y=t.useRef(0),T=t.useRef(0),[$,F]=t.useState(null),A=!d;t.useEffect(()=>{if(!A)return;let w=!0;const p=async()=>{const Z=Math.round(y.current);if(!(Z<=0)){y.current=0;try{const Q=await I.liveRecWatch(n.recording_id,{cw_uuid:l,...h?{cohort_id:h}:{},played_sec:Z});if(!w||!Q.recorded)return;F({percent:Q.percent||0,completed:!!Q.completed,granted:!!Q.makeup_attendance_granted}),Q.makeup_attendance_granted&&v?.()}catch{y.current+=Z}}},K=window.setInterval(p,Zi*1e3);return()=>{w=!1,window.clearInterval(K),p()}},[n.recording_id,l,h,A]),t.useEffect(()=>{if(!r.current)return;const w=n.hls_url?{src:n.hls_url,type:"application/x-mpegURL"}:n.dash_url?{src:n.dash_url,type:"application/dash+xml"}:null;if(!w)return;const p=Us(r.current,{controls:!0,preload:"auto",fluid:!0,playbackRates:[.75,1,1.25,1.5,2],sources:[w],poster:n.thumbnail_url});i.current=p,T.current=0;const K=()=>{const Q=p.currentTime()||0,g=Q-T.current;T.current=Q,g>0&&g<2&&(y.current+=g)},Z=()=>{T.current=p.currentTime()||0};return p.on("timeupdate",K),p.on("seeked",Z),()=>{try{p.off("timeupdate",K),p.off("seeked",Z),p.dispose()}catch{}i.current=null}},[n.hls_url,n.dash_url,n.thumbnail_url]);const N=$?.percent??(n.duration_sec>0&&n.watched_sec?Math.min(100,Math.round(n.watched_sec/n.duration_sec*100)):0),b=$?.granted||n.makeup_granted,k=$?.completed??n.watch_completed;return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"live-recs__player","data-vjs-player":!0,children:e.jsx("video",{ref:r,className:"video-js vjs-default-skin vjs-big-play-centered",playsInline:!0})}),A&&e.jsxs("div",{className:"live-recs__watch",children:[e.jsx("div",{className:"live-recs__watchbar",children:e.jsx("div",{style:{width:`${N}%`}})}),e.jsxs("span",{className:"live-recs__watchtext",children:["시청 ",N,"%",b?" · 보충 출석이 인정되었습니다":n.allow_makeup_attendance?k?" · 시청 완료":" · 끝까지 보면 보충 출석으로 인정됩니다":""]})]})]})},Ji=({blockId:n,cwUuid:l,cohortId:h,canManage:d,refreshKey:v})=>{const[r,i]=t.useState([]),[y,T]=t.useState(!0),[$,F]=t.useState(null),[A,N]=t.useState(null),[b,k]=t.useState(null),[w,p]=t.useState([]),[K,Z]=t.useState(!1),Q=t.useCallback(async()=>{try{const u=await I.getLiveRecordings(n,l,h);i(u.recordings||[]),k(null)}catch(u){k(u?.response?.data?.detail||"녹화 목록을 불러오지 못했습니다.")}finally{T(!1)}},[n,l,h]);t.useEffect(()=>{Q()},[Q,v]),t.useEffect(()=>{if(!r.some(H=>H.status==="recording"||H.status==="uploading"||H.status==="processing"))return;const q=window.setInterval(()=>{Q()},1e4);return()=>window.clearInterval(q)},[r,Q]);const g=async(u,q)=>{N(u.recording_id);try{await I.updateLiveRecording(u.recording_id,q),await Q()}catch(H){alert(H?.response?.data?.detail||"변경에 실패했습니다.")}finally{N(null)}},B=u=>{p(q=>q.includes(u)?q.filter(H=>H!==u):[...q,u])},W=async()=>{if(w.length<2)return;const u=w.map(H=>r.find(Y=>Y.recording_id===H)?.title||H).map((H,Y)=>`${Y+1}. ${H}`).join(`
3`),q=window.confirm(`선택한 순서대로 하나로 합칩니다.
4
5${u}
6
7[확인] 합친 뒤 원본 파트를 삭제합니다
8[취소] 원본 파트를 그대로 남깁니다`);Z(!0);try{await I.mergeLiveRecordings({cw_uuid:l,recording_ids:w,delete_sources:q}),p([]),await Q()}catch(H){alert(H?.response?.data?.detail||"합치기를 시작할 수 없습니다.")}finally{Z(!1)}},O=async u=>{if(window.confirm(`"${u.title}" 녹화를 삭제합니다. 영상 파일도 함께 지워지며 되돌릴 수 없습니다.`)){N(u.recording_id);try{await I.deleteLiveRecording(u.recording_id,l),$===u.recording_id&&F(null),await Q()}catch(q){alert(q?.response?.data?.detail||"삭제에 실패했습니다.")}finally{N(null)}}};if(y)return e.jsx("p",{className:"live-recs__empty",children:"녹화를 확인하고 있습니다..."});if(b)return e.jsx("p",{className:"live-recs__empty live-recs__empty--err",children:b});if(!r.length)return e.jsx("p",{className:"live-recs__empty",children:d?'아직 녹화가 없습니다. 회
8의에 입장한 뒤 화면 아래 "녹화 시작" 을 누르면 서버가 녹화합니다.':"공개된 녹화가 없습니다."});const G=r.some(u=>u.part_total>1);return e.jsxs("div",{className:"live-recs",children:[d&&G&&w.length===0&&e.jsxs("p",{className:"live-recs__note live-recs__note--tip",children:["한 회의가 여러 파트로 나뉘어 저장됐습니다. 쓸 파트 하나만 ",e.jsx("b",{children:"공개"}),"하거나, 체크해서 ",e.jsx("b",{children:"하나로 합칠"})," 수 있습니다."]}),d&&w.length>0&&e.jsxs("div",{className:"live-recs__mergebar",children:[e.jsxs("span",{children:[e.jsxs("b",{children:[w.length,"개"]})," 선택 — 체크한 순서대로 이어붙입니다"]}),e.jsx("button",{className:"live-recs__mergebtn",onClick:W,disabled:K||w.length<2,children:K?"합치는 중...":"하나로 합치기"}),e.jsx("button",{className:"live-recs__mergecancel",onClick:()=>p([]),disabled:K,children:"선택 해제"})]}),r.map(u=>{const q=$===u.recording_id,H=A===u.recording_id;return e.jsxs("div",{className:`live-recs__item ${q?"open":""}`,children:[e.jsxs("div",{className:"live-recs__row",children:[d&&u.status==="ready"&&u.playable&&e.jsxs("label",{className:"live-recs__pick",title:"합치기 대상 선택 (고른 순서대로 이어붙입니다)",children:[e.jsx("input",{type:"checkbox",checked:w.includes(u.recording_id),onChange:()=>B(u.recording_id),disabled:K}),w.includes(u.recording_id)&&e.jsx("span",{className:"live-recs__picknum",children:w.indexOf(u.recording_id)+1})]}),e.jsxs("div",{className:"live-recs__meta",children:[e.jsx("b",{className:"live-recs__title",children:u.title}),e.jsxs("span",{className:"live-recs__sub",children:[u.part_total>1&&e.jsxs("b",{className:"live-recs__part",children:["파트 ",u.part,"/",u.part_total]}),u.merged_from&&u.merged_from.length>0&&e.jsxs("b",{className:"live-recs__part live-recs__part--merged",children:["합본 ",u.merged_from.length,"개"]}),Qi(u.started_at)," · ",Ki(u.duration_sec),d&&u.recorded_by_name?` · ${u.recorded_by_name}`:"",d&&typeof u.watch_count=="number"&&u.watch_count>0?` · 시청 ${u.watch_count}명 (완료 ${u.watch_completed_count??0}명)`:""]})]}),u.status==="ready"&&u.playable?e.jsx("button",{className:"live-recs__btn",onClick:()=>F(q?null:u.recording_id),children:q?"닫기":"재생"}):u.status==="recording"?e.jsxs("span",{className:"live-recs__badge live-recs__badge--live",children:[e.jsx("i",{className:"live-recs__livedot"})," 녹화 중"]}):u.status==="uploading"?e.jsx("span",{className:"live-recs__badge live-recs__badge--wait",children:"녹화 파일 생성 중"}):u.status==="processing"?e.jsx("span",{className:"live-recs__badge live-recs__badge--wait",children:u.encoding_progress?`변환 중 ${u.encoding_progress}%`:"변환 중"}):u.status==="failed"?e.jsx("span",{className:"live-recs__badge live-recs__badge--err",title:u.error_message||"",children:"실패"}):e.jsx("span",{className:"live-recs__badge",children:u.status})]}),q&&u.playable&&e.jsx(Yi,{rec:u,cwUuid:l,cohortId:h,canManage:d,onGranted:()=>{Q()}}),d&&!u.awaiting_file&&e.jsxs("div",{className:"live-recs__admin",children:[e.jsxs("label",{className:"live-recs__field",children:[e.jsx("span",{children:"공개"}),e.jsx("input",{type:"checkbox",checked:!!u.published,disabled:H,onChange:Y=>g(u,{cw_uuid:l,published:Y.target.checked})})]}),e.jsxs("label",{className:"live-recs__field",children:[e.jsx("span",{children:"대상"}),e.jsx("select",{value:u.visible_to||"absent",disabled:H,onChange:Y=>g(u,{cw_uuid:l,visible_to:Y.target.value}),children:Object.entries(Xi).map(([Y,pe])=>e.jsx("option",{value:Y,children:pe},Y))})]}),e.jsxs("label",{className:"live-recs__field",title:"녹화를 끝까지 본 학습자를 ë³´ì¶© 출석으로 인정합니다",children:[e.jsx("span",{children:"ë³´ì¶© 출석 인정"}),e.jsx("input",{type:"checkbox",checked:!!u.allow_makeup_attendance,disabled:H,onChange:Y=>g(u,{cw_uuid:l,allow_makeup_attendance:Y.target.checked})})]}),e.jsx("a",{className:"live-recs__dl",href:`${oi}/lms/live-recording/download/${u.recording_id}?cw_uuid=${encodeURIComponent(l)}`,title:"녹화 원본 mp4 다운로드",children:"mp4 다운로드"}),e.jsx("button",{className:"live-recs__del",disabled:H,onClick:()=>O(u),children:"삭제"})]}),d&&(u.status==="uploading"||u.status==="processing")&&e.jsx("p",{className:"live-recs__waitmsg",children:u.status==="uploading"?"화상수업 서버가 녹화 파일ì
8„ 만들어 전송하고 있습니다. 녹화 길이에 따라 수 분 걸릴 수 있습니다.":"영상을 변환하고 있습니다. 끝나면 바로 재생할 수 있습니다."}),d&&u.status==="failed"&&u.error_message&&e.jsx("p",{className:"live-recs__errmsg",children:u.error_message})]},u.recording_id)}),!d&&e.jsx("p",{className:"live-recs__note",children:"공개된 녹화만 표시됩니다. 수업에 참여하지 못한 경우 이 녹화로 학습할 수 있습니다."})]})},Yn=n=>Array.from({length:n},()=>({top:12+Math.random()*62,left:4+Math.random()*74})),Ui=({label:n,intervalMs:l=18e4,count:h=2})=>{const v=di()?.user,r=t.useMemo(()=>{if(n)return n;if(!v)return"";const T=v.identity_number||v.username||"";return String(T).trim()},[n,v]),[i,y]=t.useState(()=>Yn(h));return t.useEffect(()=>{if(!r)return;const T=window.setInterval(()=>y(Yn(h)),l);return()=>window.clearInterval(T)},[r,l,h]),r?e.jsx("div",{className:"video-watermark","aria-hidden":"true",children:i.map((T,$)=>e.jsx("span",{className:"video-watermark-mark",style:{top:`${T.top}%`,left:`${T.left}%`},children:r},$))}):null},Jn={active:!1,state:"none",start:null,end:null},Un=n=>{if(n instanceof Date)return Number.isNaN(n.getTime())?null:n;const l=String(n??"").trim();if(!l)return null;const h=new Date(l.replace(" ","T"));if(!Number.isNaN(h.getTime()))return h;const d=l.match(/\d+/g);if(!d||d.length<3)return null;const[v,r,i]=[Number(d[0]),Number(d[1]),Number(d[2])];if(!v||!r||!i||r>12||i>31)return null;const y=new Date(v,r-1,i,Number(d[3]||0),Number(d[4]||0),Number(d[5]||0));return Number.isNaN(y.getTime())?null:y},xs=(n,l=Js())=>{const h=n?.attendance_period,d=h?.active===!0||h?.active==="True"||h?.active==="true";if(!h||!d)return Jn;const v=Un(h.startdate),r=Un(h.enddate);return!v&&!r?Jn:{active:!0,state:v&&l<v?"before":r&&l>r?"closed":"open",start:v,end:r}},ea=n=>String(n).padStart(2,"0"),ta=n=>n?`${String(n.getFullYear()).slice(2)}.${ea(n.getMonth()+1)}.${ea(n.getDate())}`:"",Et=n=>{if(!n.active)return"";const l=ta(n.start),h=ta(n.end);return l&&h?`${l}~${h}`:h?`~${h}`:l?`${l}~`:""},sa=n=>n.state==="closed"?"기간 지남":n.state==="before"?"시작 전":n.state==="open"?"학습 가능":"",en=n=>{if(!n.active)return"";const l=h=>h?h.toLocaleString("ko-KR"):"?";return`학습 인정 기간: ${l(n.start)} ~ ${l(n.end)}
9${n.state==="closed"?"기간이 지났습니다.":n.state==="before"?"아직 시작 전입니다.":"지금 들을 수 있습니다."}`},Ys=n=>{if(!n)return null;const l=n.video_thumbnail_url||n.thumbnail_url;if(l)return String(l);const h=String(n.video_thumbnail_uri||"");if(h)return h;const d=String(n.uri||"");if(!d)return null;const v=d.match(/(?:youtube\.com\/(?:embed\/|watch\?v=)|youtu\.be\/)([\w-]{6,})/);return v?`https://i.ytimg.com/vi/${v[1]}/mqdefault.jpg`:d.startsWith("/legacy-video/")?`/api/lms/legacy-thumbnail?uri=${encodeURIComponent(d)}`:null},Ht=n=>n?n.replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/\s+/g," ").trim():"",er=15e3,tr=({blockId:n,cwUuid:l,cohortId:h,onClose:d,onNavigate:v})=>{const{t:r}=gs("lms"),[i,y]=t.useState(null),[T,$]=t.useState(!0),[F,A]=t.useState(null),[N,b]=t.useState(null),[k,w]=t.useState(null),[p,K]=t.useState(null),[Z,Q]=t.useState(!1),[g,B]=t.useState({}),[W,O]=t.useState(()=>{try{return localStorage.getItem("lms_auto_next_video")==="1"}catch{return!1}}),[G,u]=t.useState(null),[q,H]=t.useState(!1),[Y,pe]=t.useState([]),[ye,C]=t.useState({prev:null,next:null}),[o,z]=t.useState("video"),R=t.useRef(null),m=t.useRef(null),J=t.useRef(0),ve=t.useRef(Date.now()),xe=t.useRef(null),Ie=t.useRef(null),oe=t.useRef(null),[ee,de]=t.useState(null),[Te,Ze]=t.useState(!1),[ue,$e]=t.useState(!1),Oe=t.useRef(null),[Ve,Ge]=t.useState(null),[Pe,me]=t.useState(0),[Re,Ye]=t.useState(""),[nt,Pt]=t.useState(""),[Le,_]=t.useState("single_multiple_choice"),[L,X]=t.useState(5),[M,ae]=t.useState([]),[x,ge]=t.useState(""),[te,Ee]=t.useState(""),[qe,we]=t.useState([]),[U,re]=t.useState(""),[se,Be]=t.useState(!1),[ze,Ke]=t.useState(null),[Rt,sn]=t.useState(!1),[ca,oa]=t.useState(""),[nn,da]=t.useState(""),[vs,ua]=t.useState(100),[ut,ma]=t.useState("uploadfile"),[mt,ha]=t.useState(1),[Gt,pa]=t.useState(20),[Kt,xa]=t.useState(""),[at,ga]=t.useState(""),[an,fa
9]=t.useState([]),[Qt,Mt]=t.useState("none"),[js,bs]=t.useState(""),[bt,Xt]=t.useState([]),[rn,ys]=t.useState(null),[yt,_s]=t.useState(null),[ln,cn]=t.useState(!1),[on,dn]=t.useState(!1),_t=t.useRef(null),[va,un]=t.useState(!1),[fe,ja]=t.useState([]),[At,Ns]=t.useState({}),[Zt,ks]=t.useState({}),[Ue,ws]=t.useState(!1),[Qe,Ss]=t.useState(null),[Cs,mn]=t.useState(!1),[ne,Yt]=t.useState(0),[Ts,hn]=t.useState(null),[Es,pn]=t.useState(!1),Jt=t.useRef(null),xn=t.useRef(()=>{}),[ba,gn]=t.useState(null),[fn,ya]=t.useState(null),[ht,Ut]=t.useState(null),et=t.useRef(null),[_a,Na]=t.useState(""),[es,ka]=t.useState(null),[Nt,wa]=t.useState("instructor_managed"),[pt,Sa]=t.useState(null),[Ca,Ta]=t.useState(10),[Se,ts]=t.useState(null),[vn,jn]=t.useState(!1),[bn,Ls]=t.useState(!1),[yn,tt]=t.useState(null),[it,_n]=t.useState(null),[We,Ps]=t.useState([]),[xt,ss]=t.useState(!0),Rs=t.useRef(0),ns=t.useRef(0),gt=t.useRef(!1),Xe=t.useRef(null),as=t.useRef(null),[ft,Ms]=t.useState(null),[$t,Nn]=t.useState("panel"),[is,zt]=t.useState(!1),[vt,As]=t.useState(-1),[lr,kn]=t.useState(!1),[wn,Sn]=t.useState(!1),Ea=t.useRef(null),rs=t.useRef(null),rt=t.useRef(null),$s=t.useRef(null),[kt,Cn]=t.useState("transcript"),[Dt,La]=t.useState([]),[wt,Tn]=t.useState([]),[Pa,zs]=t.useState(""),Ra=s=>{const a=[];return s.trim().split(/\n\n+/).forEach((f,j)=>{const P=f.split(`
10`);if(P.length>=3){const S=P[1].match(/(\d{2}):(\d{2}):(\d{2})[,.](\d{3})\s*-->\s*(\d{2}):(\d{2}):(\d{2})[,.](\d{3})/);if(S){const le=parseInt(S[1])*3600+parseInt(S[2])*60+parseInt(S[3])+parseInt(S[4])/1e3,Ne=parseInt(S[5])*3600+parseInt(S[6])*60+parseInt(S[7])+parseInt(S[8])/1e3,ke=P.slice(2).join(" ").trim();a.push({id:j,startTime:le,endTime:Ne,text:ke})}}}),a},En=async s=>{try{kn(!0);const a=await fetch(s);if(a.ok){const c=await a.text(),f=Ra(c);Ps(f)}}catch(a){console.error("Failed to load transcript:",a)}finally{kn(!1)}},Ds=s=>{if(!s||s<=0)return"0:00";const a=Math.floor(s/60),c=Math.floor(s%60);return`${a}:${c.toString().padStart(2,"0")}`},Ma=()=>{if(!p||!p.achieve)return{status:r("videoPlayer.status.incomplete","미완료"),color:"#dc3545"};const s=i?.block_data;if(s?.learning_start_date&&s?.learning_end_date){const a=new Date(s.learning_end_date);if((p.achieve_detail?.completed_at?new Date(p.achieve_detail.completed_at):new Date)>a)return{status:r("videoPlayer.status.lateComplete","지각완료"),color:"#ff8c00"}}return{status:r("videoPlayer.status.complete","완료"),color:"#28a745"}},Aa=()=>{if(o==="quiz")return se&&ze?{status:ze.is_correct?r("videoPlayer.status.correct","정답"):r("videoPlayer.status.incorrect","오답"),color:ze.is_correct?"#28a745":"#dc3545"}:{status:r("videoPlayer.status.incomplete","미완료"),color:"#dc3545"};if(o==="assignment")switch(Qt){case"submitted":return{status:r("videoPlayer.status.submitted","제출완료"),color:"#007bff"};case"graded":return{status:r("videoPlayer.status.graded","채점완료"),color:"#28a745"};case"returned":return{status:r("videoPlayer.status.returned","반려됨"),color:"#dc3545"};default:return{status:r("videoPlayer.status.notSubmitted","미제출"),color:"#dc3545"}}else if(o==="attendance"){if(he)return{status:r("videoPlayer.status.teacherView","교수자 보기"),color:"#6c757d"};if(Se?.status)switch(Se.status){case"PRESENT":return{status:r("videoPlayer.status.present","출석"),color:"#28a745"};case"LATE":return{status:r("videoPlayer.status.late","지각"),color:"#ff8c00"};case"ABSENT":return{status:r("videoPlayer.status.absent","결석"),color:"#dc3545"};case"EXCUSED":return{status:r("videoPlayer.status.excused","공결"),color:"#6c757d"}}return{status:Se?.can_checkin?r("videoPlayer.status.canCheckin","출석 가능"):r("videoPlayer.status.notCheckedIn","미출석"),color:"#dc3545"}}else{if(o==="live")return he?{status:r("videoPlayer.status.teacherView","교수자 보기"),color:"#6c757d"}:ee?.attended?{status:r("videoPlayer.status.present","출석"),color:"#28a745"}:{status:r("videoPlayer.status.notCheckedIn","미입장"),color:"#dc3545"};if(["material","learning_material","etc_material"].includes(o))return{status:Tt(o),color:"#d97706"}}return Ma()},ls=t.useCallback(async()=>
10{if(l)try{const s=await I.getMyBlockProgress(l,h),a={};(s.items||[]).forEach(c=>{a[c.block_id]=c}),B(a)}catch(s){console.error("Failed to load block progress:",s)}},[l,h]);t.useEffect(()=>{ls()},[ls,n]),t.useEffect(()=>{Ms(null);const s=i?.block_data?.content?.video;if(!s||s.video_type==="youtube"||s.video_type==="cdn")return;const a=s.encoded_uri||s.uri||s.video_id||"",c=String(a).match(/upload_[^/.\s]+/);if(!c)return;let f=!1,j=null;const P=async()=>{try{const D=await Ce.get(`/lms/video/${c[0]}/status`);if(f)return;const S=D.data||{};Ms({status:S.status||"",progress:S.progress||0,error:S.error}),S.status&&S.status!=="completed"&&S.status!=="failed"&&(j=setTimeout(P,1e4))}catch{f||Ms(null)}};return P(),()=>{f=!0,j&&clearTimeout(j)}},[n,i]);const Ln=s=>{const a=g[s];if(!a)return null;if(a.achieve)return 100;const c=Number(a.progress_percent||0);return c>0?Math.min(99,Math.round(c)):0},Is=s=>!!g[s]?.achieve,It=t.useMemo(()=>{const s=[];return Y.forEach(a=>{a.sessions?.forEach(c=>{c.blocks?.forEach(f=>{f.blockType?.toLowerCase()==="video"&&f.blockId&&s.push({blockId:f.blockId,title:Ht(f.title||c.sessionTitle||""),label:`${a.moduleNumber}${r("videoPlayer.week","주차")} ${c.sessionNumber}${r("videoPlayer.session","차시")}`})})})}),s},[Y,r]),Bs=t.useCallback(()=>{const s=It.findIndex(c=>c.blockId===n);return(s>=0?It.slice(s+1):It).find(c=>!g[c.blockId]?.achieve)||It.find(c=>c.blockId!==n&&!g[c.blockId]?.achieve)||null},[It,n,g]),Ws=t.useRef(W),Fs=t.useRef(Bs);t.useEffect(()=>{Ws.current=W},[W]),t.useEffect(()=>{Fs.current=Bs},[Bs]);const $a=s=>{O(s);try{localStorage.setItem("lms_auto_next_video",s?"1":"0")}catch{}},St=(s,a)=>{v&&v(s,a)},za=o==="notice",[De,Bt]=t.useState(null),[qs,Os]=t.useState(null),[Ct,Pn]=t.useState("unread"),[he,Hs]=t.useState(!1);t.useEffect(()=>{if(!l){Hs(!1);return}let s=!0;return Ce.get("/lms/grade-by-block/instructor/can-manage",{params:{cw_uuid:l}}).then(a=>{s&&Hs(!!(a.data?.canManage??a.data?.can_manage))}).catch(()=>{s&&Hs(!1)}),()=>{s=!1}},[l]),t.useEffect(()=>{!De?.loading||!l||!n||Ce.get(`/lms/cws-notices/${l}/readers/block/${encodeURIComponent(n)}`).then(s=>{Bt(s.data),Os({read:s.data?.read_count||0,total:s.data?.total_students||0})}).catch(s=>Bt({error:s?.response?.data?.detail||"불러오지 못했습니다."}))},[De?.loading,l,n]),t.useEffect(()=>{if(Os(null),!he||!l||o!=="notice"||!n)return;let s=!0;return Ce.get(`/lms/cws-notices/${l}/readers/block/${encodeURIComponent(n)}`).then(a=>{s&&Os({read:a.data?.read_count||0,total:a.data?.total_students||0})}).catch(()=>{}),()=>{s=!1}},[he,l,n,o]);const Rn=["learning_material","etc_material"],Mn=["material",...Rn].includes(o),Da=s=>{const a=s?.block_data?.content||{},c=(j,P,D=0)=>{const S=(j.split(".").pop()||"").toLowerCase();return{file_id:`mat_${P.split("/").pop()||j}`,file_name:j,file_path:P,file_type:S==="pdf"?"pdf":S==="ipynb"?"ipynb":["hwp","hwpx","hml"].includes(S)?"hwp":Ni(j)?"office":"zip",file_size:D,uploaded_at:""}},f=Rn.find(j=>a[j]);if(f){const j=a[f];return(Array.isArray(j)?j:[j]).filter(D=>D&&D.uri).map(D=>c(D.material_title||(D.uri||"").split("/").pop()||"자료",D.uri))}return(a.files||[]).map(j=>{const P=(j.file_path||"").split("/").pop()||"";return c(j.file_name||P,`/api/cms/board_material_view/${P}`,j.file_size||0)})};t.useEffect(()=>{if(!n)return;let s=!0;const a=()=>{!s||document.visibilityState!=="visible"||fetch("/api/sso/keepalive",{method:"POST",credentials:"include"}).catch(()=>{})};a();const c=window.setInterval(a,300*1e3);return()=>{s=!1,window.clearInterval(c)}},[n]);const lt=ba??N?.learning_window??null,Wt=lt?.open===!1,Ia=Wt?lt?.message:void 0,Ba=Wt?lt?.state==="before"?"학습 기간 전 — 제출 불가":lt?.scope==="semester"?"학기 종료 — 제출 불가":"학습 기간 종료 — 제출 불가":"",ct=xs(i?.block_data?.content),Vs=ct.active&&(ct.state==="before"||ct.state==="closed"),Wa=ct.state==="before"?"기간 전 — 제출 불가":"기간 마감 — 제출 불가",Fa=Vs?en(ct):void 0,ot=Wt||Vs,cs=Wt?Ba:Wa,os=Ia||Fa,Ft=()=>{l&&I.getLearningWindow(l).then(gn).catch(()=>{})};t.useEffect(()=>{gn(null),Ft()},[l]);const ds=s=>{const a=s?.response?.data?.detail;
10return typeof a=="string"?a:a&&typeof a=="object"&&a.message?String(a.message):s?.message||r("videoPlayer.errors.unknownError","알 수 없는 오류")},jt=s=>{if(!s)return;const a=s.recognized===!1||s.recorded===!1;ya(a?s.message||"지금 시청한 것은 진도로 인정되지 않습니다.":null),K(s)};t.useEffect(()=>{if(Ut(null),o!=="exam"||!l||!i?.block_data?.content?.time_limit?.active)return;let s=!0;return I.getExamSession(n,l).then(a=>{s&&Ut(a)}).catch(()=>{}),()=>{s=!1}},[n,l,o,i]);const qt=ht?.state==="ended",An=ht?.started_at?`${Vt(ht.started_at)} ~ ${Vt(ht.deadline)}`:"",us=s=>ra(s),Tt=s=>ia(s,r,"videoPlayer.blockTypes");t.useEffect(()=>{if(Ie.current&&n){Ie.current.scrollTop=0;const s=setTimeout(()=>{Ie.current&&(Ie.current.scrollTop=0)},100);return()=>clearTimeout(s)}},[n]),t.useEffect(()=>{(async()=>{try{$(!0),A(null),Be(!1),Ke(null),we([]),re(""),Mt("none"),bs(""),Xt([]),ys(null),_s(null),ts(null),tt(null),_n(null);const a=n.startsWith("attend_");let c,f;a?[c,f]=await Promise.all([I.getAttendanceBlock(n),I.getCWSItem(l)]):[c,f]=await Promise.all([I.getBlock(n),I.getCWSItem(l)]),y(c),b(f);const j=c.block_data?.content?.attachments;j&&Array.isArray(j)&&La(j);let P;if(a?P="attendance":P=c.block_type||c.block_data?.meta?.block_type||c.block_data?.blockType||c.blockType||"video",c.block_type,z(P.toLowerCase()),P.toLowerCase()==="quiz"?await $n(c):P.toLowerCase()==="assignment"?await Ga(c):P.toLowerCase()==="exam"?await zn(c):P.toLowerCase()==="attendance"&&await Ka(c),f.course_structure&&Array.isArray(f.course_structure)){pe(f.course_structure);const D=[];for(const le of f.course_structure)for(const Ne of le.sessions||[])for(const ke of Ne.blocks||[])D.push({id:ke.blockId,type:ke.blockType||"video"});const S=D.findIndex(le=>le.id===n);S!==-1&&C({prev:S>0?D[S-1]:null,next:S<D.length-1?D[S+1]:null});for(const le of f.course_structure)for(const Ne of le.sessions||[])if((Ne.blocks||[]).find(Je=>Je.blockId===n)){w({moduleTitle:le.moduleTitle,moduleNumber:le.moduleNumber,sessionNumber:Ne.sessionNumber,sessionTitle:Ne.sessionTitle});break}}}catch(a){console.error("Failed to load block:",a),A(r("videoPlayer.loadError","블록 데이터를 불러오는데 실패했습니다."))}finally{$(!1)}})()},[n,l]);const qa=s=>({ko:"한국어",en:"English",zh:"中文",ja:"日本語",es:"Español",fr:"Français",de:"Deutsch",ru:"Русский",ar:"العربية",pt:"Português",it:"Italiano",vi:"Tiếng Việt",th:"ไทย",id:"Indonesia"})[s]||s.toUpperCase();t.useEffect(()=>{if(Ps([]),As(-1),Tn([]),zs(""),o==="video"&&i){const s=i?.block_data?.content?.subtitles;if(s&&s.length>0){const a=s.map(f=>({lang:f.lang,label:qa(f.lang),path:f.path}));Tn(a);const c=s[0];c?.path&&(zs(c.lang),En(c.path))}}o==="notice"&&i&&n&&l&&Ce.post(`/lms/cws-notices/${l}/read/block/${encodeURIComponent(n)}`).catch(()=>{}),["material","learning_material","etc_material"].includes(o)&&i&&n&&fetch("/api/lms/material/track",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({block_id:n,file_id:"",action:"view"})}).catch(()=>{})},[i,o]),t.useEffect(()=>{if(o!=="live"||!i||!n||!l)return;let s=!0;return I.getLiveStatus(n,l,h).then(a=>{s&&de(a)}).catch(()=>{}),()=>{s=!1}},[o,i,n,l,h]),t.useEffect(()=>{if(o!=="live"||!i||!n||!l||he||ue||ee&&ee.host_active)return;let s=!0;const a=window.setInterval(()=>{I.getLiveStatus(n,l,h).then(c=>{s&&de(c)}).catch(()=>{})},er);return()=>{s=!1,window.clearInterval(a)}},[o,i,n,l,h,he,ue,ee?.host_active]);const Oa=async()=>{if(o==="live"&&ue){const s=he?`수업을 종료하고 창을 닫을까요?
11참여자 전원이 회의에서 나가고, 진행 중인 서버 녹화도 종료됩니다.`:`회의에서 나가고 창을 닫을까요?
12나가면 시청 시간 인정이 멈춥니다.`;if(!window.confirm(s))return;try{await Oe.current?.()}catch{}$e(!1)}d()},Ha=async()=>{const a=(i?.block_data?.content||{}).live||{},f=(a.platform||"jitsi")==="jitsi",j=a.room_id||"",P=a.url||"",D=f?"iframe":a.open_mode||"both";if(f?!(j||P):!P){alert("회의 정보가 설정되지 않았습니다.");return}Ze(!0);try{if(!he){const S=await I.liveCheckin(n,{cw_uuid:l,...h?{cohort_id:h}:{}});de(le=>({...le||{},attended:!0,status:S.status}))}!f&&(D==="newwindow"||D==="both"||D==="iframe")&&window.open(P,"_blank","noopener,noreferrer"),(f||D==="iframe"||D==="both")&&$e(!0)}catch(S){alert(S?.response?.data?.detail||"입장 처리에 실패했습니다.")}finally{Ze(!1)}},Va=s=>{const a=wt.find(c=>c.lang===s);a&&(zs(s),Ps([]),As(-1),En(a.path))};t.useEffect(()=>{if(m.current&&We.length>0){const s=m.current,a=()=>{const c=s.currentTime(),f=We.findIndex(j=>c>=j.startTime&&c<j.endTime);f!==-1&&f!==vt&&As(f)};return s.on("timeupdate",a),()=>{s&&!s.isDisposed()&&s.off("timeupdate",a)}}},[We,vt]),t.useEffect(()=>{if(vt!==-1&&!wn&&rs.current){const s=rs.current.querySelector(".transcript-line.active");if(s){const a=rs.current,c=a.clientHeight,f=s.offsetTop-a.offsetTop,j=s.clientHeight,P=f-c/2+j/2;a.scrollTo({top:Math.max(0,P),behavior:"smooth"})}}},[vt,wn]);const Gs=()=>{Sn(!0),rt.current&&(clearTimeout(rt.current),rt.current=null)},Ks=()=>{rt.current&&clearTimeout(rt.current),rt.current=setTimeout(()=>{Sn(!1)},3e3)};t.useEffect(()=>()=>{rt.current&&clearTimeout(rt.current)},[]),t.useEffect(()=>{const s=a=>{$s.current&&!$s.current.contains(a.target)&&zt(!1)};return is&&document.addEventListener("mousedown",s),()=>{document.removeEventListener("mousedown",s)}},[is]);const $n=async s=>{const a=s.block_data?.content||{};Ye(a.title||s.title||""),Pt(a.description||""),_(a.quiz_type||"single_multiple_choice"),X(a.score??5),ae(a.options||[]),ge(a.feedback?.correct||""),Ee(a.feedback?.incorrect||"");try{const c=await I.getQuizGrade(n,h);c&&c.submission&&(Be(!0),c.submission.answer_indexes&&we(c.submission.answer_indexes),c.submission.answer_text&&re
12(c.submission.answer_text),c.result&&Ke(c.result))}catch{}},Ga=async s=>{const a=s.block_data?.content||{};oa(a.title||s.title||""),da(a.description||""),ua(a.max_score??100);const c=a.submission_settings||{};ma(c.method||"uploadfile"),ha(c.max_file_count||1),pa(c.max_file_size_mb||20);const f=a.attendance_period||{};f.startdate&&xa(f.startdate),f.enddate&&ga(f.enddate),fa(a.instructor_files||[]);try{const j=await I.getAssignmentGrade(n,h);j&&j.submission&&(Mt(j.achieve_detail?.status||"submitted"),ys(j.submission.submitted_at||null),j.submission.text_content&&bs(j.submission.text_content),j.submission.files&&Xt(j.submission.files),j.result&&(_s(j.result),j.result.is_graded&&Mt("graded")))}catch{}},zn=async s=>{const a=s.block_data?.content||{},c=a.quiz_bank_items||[],j=(a.questions||[]).map((P,D)=>{const S=c.find(le=>le.quiz_ref_id===P.quiz_ref_id||c.indexOf(le)===D)||c[D];return{index:D,quiz_ref_id:P.quiz_ref_id,allocated_score:P.allocated_score||10,type:S?.type||"single_choice",title:S?.content?.title||`문항 ${D+1}`,description:S?.content?.description||"",options:S?.content?.options||[],correct_short_answer:S?.content?.correct_short_answer||""}});ja(j);try{const P=await I.getExamGrade(n,h);P&&P.submission&&(ws(!0),un(!0),P.submission.answers&&Ns(P.submission.answers),P.submission.text_answers&&ks(P.submission.text_answers),P.result&&Ss(P.result))}catch{}},Ka=async s=>{const a=s.block_data||s;Na(s.title||a.title||""),ka(a.session_info||null),wa(a.attendance_method||"instructor_managed"),Sa(a.gps_location||null),Ta(a.gps_radius_meters||10);try{const c=await I.getMyAttendanceStatus(n);ts(c)}catch(c){console.error("Failed to load attendance status:",c),ts({status:null,can_checkin:!0,message:r("videoPlayer.attendance.statusLoadFailed","출석 상태를 불러오지 못했습니다.")})}},Qa=()=>
12{if(!navigator.geolocation){tt(r("videoPlayer.attendance.geoNotSupported","브라우저에서 위치 서비스를 지원하지 않습니다."));return}Ls(!0),tt(null),navigator.geolocation.getCurrentPosition(s=>{_n({latitude:s.coords.latitude,longitude:s.coords.longitude,accuracy:s.coords.accuracy}),Ls(!1)},s=>{switch(Ls(!1),s.code){case s.PERMISSION_DENIED:tt(r("videoPlayer.attendance.geoPermissionDenied","위치 권한이 거부되었습니다."));break;case s.POSITION_UNAVAILABLE:tt(r("videoPlayer.attendance.geoUnavailable","위치 정보를 사용할 수 없습니다."));break;case s.TIMEOUT:tt(r("videoPlayer.attendance.geoTimeout","위치 요청 시간이 초과되었습니다."));break;default:tt(r("videoPlayer.attendance.geoUnknownError","알 수 없는 오류가 발생했습니다."))}},{enableHighAccuracy:!0,timeout:1e4,maximumAge:0})},Xa=async()=>{jn(!0),tt(null);try{const s={};Nt==="student_checkin"&&pt&&it&&(s.latitude=it.latitude,s.longitude=it.longitude,s.accuracy=it.accuracy);const a=await I.studentCheckin(n,s);ts({status:a.status,checkin_time:a.checkin_time,can_checkin:!1,message:a.message})}catch(s){const a=s.response?.data?.detail||r("videoPlayer.attendance.checkinFailed","출석 체크에 실패했습니다.");tt(a)}finally{jn(!1)}},Za=async()=>{if(Es)return;pn(!0);let s;try{s=await I.startExam({block_id:n,cw_uuid:l,...h?{cohort_id:h}:{}})}catch(c){alert("시험을 시작할 수 없습니다: "+ds(c)),Ft(),I.getExamSession(n,l).then(Ut).catch(()=>{});return}finally{pn(!1)}if(un(!0),Yt(0),Ns({}),ks({}),ws(!1),Ss(null),et.current&&clearInterval(et.current),s?.deadline&&Ut(s),Jt.current=s?.deadline?Date.parse(s.deadline):null,Jt.current===null){hn(null);return}const a=()=>{const c=Math.max(0,Math.round((Jt.current-Js().getTime())/1e3));hn(c),c<=2&&(et.current&&clearInterval(et.current),xn.current(!0))};a(),et.current=setInterval(a,1e3),s?.resumed&&alert("진행 중이던 응시를 이어서 합니다. 제한시간은 처음 시작한 때부터 계산되며, 제출하지 않은 답은 다시 입력해야 합니다.")};t.useEffect(()=>()=>{et.current&&clearInterval(et.current)},[]);const Ya=(s,a,c)=>{Ue||Ns(f=>{const j=f[s]||[];return c?j.includes(a)?{...f,[s]:j.filter(P=>P!==a)}:{...f,[s]:[...j,a]}:{...f,[s]:[a]}})},Ja=(s,a)=>{Ue||ks(c=>({...c,[s]:a}))},Dn=async(s=!1)=>{if(Cs)return;const a=fe.filter((c,f)=>c.type==="short_answer"||c.type==="subjective"||c.type==="long_answer"?!Zt[f]?.trim():!At[f]||At[f].length===0);if(!(a.length>0&&!Ue&&!s&&!window.confirm(r("videoPlayer.exam.unansweredAlert","{{count}}개의 문항에 답하지 않았습니다. 그래도 제출하시겠습니까?",{count:a.length})))){mn(!0);try{const c={block_id:n,cw_uuid:l,...h?{cohort_id:h}:{},submission:{submitted_at:new Date().toISOString(),answers:At,text_answers:Zt}},f=await I.submitExam(c);f?.result&&Ss(f.result),ws(!0);try{await zn(await I.getBlock(n))}catch{}et.current&&clearInterval(et.current),Jt.current=null,s&&alert("제한시간이 끝나 지금까지의 답안으로 제출했습니다.")}catch(c){console.error("Failed to submit exam:",c),alert("제출에 실패했습니다: "+ds(c)),Ft()}finally{mn(!1)}}};xn.current=Dn;const Ua=s=>{const a=Math.floor(s/3600),c=Math.floor(s%3600/60),f=s%60;return a>0?`${a}:${c.toString().padStart(2,"0")}:${f.toString().padStart(2,"0")}`:`${c}:${f.toString().padStart(2,"0")}`};t.useEffect(()=>{if(o!=="video")return;(async()=>{try{Q(!1);const a=await I.getVideoProgress(n,h);K(a),xe.current=a,J.current=a.last_position_sec||0,Q(!0)}catch(a){console.error("Failed to load progress:",a)}})()},[n,o]);const In=(s,a)=>s?.achieve?a||Number.MAX_SAFE_INTEGER:Math.max(0,s?.max_position_sec||0),Bn=t.useCallback(s=>{if(!s?.el_||s.el_.querySelector(".seek-warning"))return;const a=document.createElement("div");a.className="seek-warning",a.textContent=r("videoPlayer.seekWarning","아직 보지 않은 구간으로는 건너뛸 수 없습니다."),s.el_.appendChild(a),setTimeout(()=>{a.parentNode?.removeChild(a)},2200)},[r]),ms=t.useCallback((s,a)=>{const c=s?.controlBar?.progressControl;if(!c||(c.enable(),!c.el_))return;c.el_.style.pointerEvents="auto",c.el_.style.opacity="1",c.el_.style.cursor="pointer";const f=s.duration?.()||a?.video_duration_sec||0,j=In(a,f),P=!!a?.achieve||!f||j>=f;s.el_?.classList.toggle("gp-seek-limited",!P),c.el_.style.setProperty("--gp-seen",P?"100%":`${Math.min(100,j/f*100)}%`)},[]),hs=t.useCallback(s=>{const a=xe.current;if(!a||gt.current||a.achieve)return;const c=s.duration?.()||a?.video_duration_sec||0,f=In(a,c),j=Math.max(f,Rs.current||0);s.currentTime()>j+2&&(s.currentTime(j),Bn(s))},[Bn]);t.useEffect(()=>{xe.current=p,ms(m.current,p)},[p,ms]);const Wn=async s=>{const a=Date.now();if((a-ve.current)/1e3<5)return;ve.current=a;const c=xe.current;if(!c?.achieve){const j=Math.max(0,c?.max_position_sec||0);if(s>j+2){J.current=Math.min(J.current,j);return}}const f=s-J.current;if(f<=0||f>=30){J.current=s;return}try{const j=await I.updateVideoProgress(n,l,s,f,h);jt(j),J.current=s}catch(j){console.error("Failed to update progress:",j)}};t.useEffect(()=>{if(o!=="video"||!i||!R.current)return;const s=i?.block_data?.content?.video;
12if(!s)return;const a=s.video_type==="youtube"&&s.uri,c=s.video_type==="cdn"&&s.uri,f=s.video_encoded===!0,j=s.encoded_uri||s.uri||"",P=/upload_[^/.\s]+/.test(j);if(!a&&!c&&!f&&!P||!Z||!p)return;if((()=>{let S=document.querySelector("link[rel*='icon']");S||(S=document.createElement("link"),S.rel="icon",document.head.appendChild(S)),S.href="/favicon.svg"})(),s.video_type==="youtube"){m.current=Us(R.current,{techOrder:["youtube"],sources:[{type:"video/youtube",src:s.uri}],controls:!0,autoplay:!1,preload:"auto",fluid:!0,playbackRates:[.5,.75,1,1.25,1.5,1.75,2],controlBar:{pictureInPictureToggle:!1,children:["playToggle","volumePanel","currentTimeDisplay","timeDivider","durationDisplay","progressControl","remainingTimeDisplay","playbackRateMenuButton","fullscreenToggle"]},youtube:{ytControls:0}}),R.current&&(R.current.disablePictureInPicture=!0);const S={done:!1,held:0},le=()=>{const V=xe.current;if(!V)return 0;const je=V.achieve?V.last_position_sec||V.max_position_sec||0:V.max_position_sec||0,_e=m.current?.duration?.()||0;return _e>0?Math.max(0,Math.min(je,_e-1)):je},Ne=()=>{if(S.done||!m.current||!xe.current)return;const V=le();if(V<=0)return;const je=m.current.tech?.(!0)?.el?.();if(je&&je.readyState<1||m.current.seeking?.()||Date.now()-(ns.current||0)<1500)return;const _e=m.current.currentTime()||0;if(Math.abs(_e-V)<1.5){S.held+=1,S.held>=3&&(S.done=!0);return}gt.current=!0,ns.current=Date.now(),m.current.currentTime(V),S.held=0,window.setTimeout(()=>{gt.current=!1},800)};m.current.ready(()=>Ne()),["loadedmetadata","loadeddata","canplay","canplaythrough","play"].forEach(V=>{m.current.on(V,Ne)}),Ne();const ke=()=>{const V=R.current,je=V?.closest(".video-player-wrapper");!V||!je||!V.videoWidth||!V.videoHeight||(je.style.setProperty("--gp-video-aspect",String(V.videoWidth/V.videoHeight)),je.style.setProperty("--gp-video-ratio",`${V.videoWidth} / ${V.videoHeight}`))};["loadedmetadata","loadeddata","canplay"].forEach(V=>{m.current.on(V,ke)}),ke();let Je=0;Xe.current=window.setInterval(()=>{Je+=1,Ne(),(S.done||Je>1500)&&Xe.current&&(window.clearInterval(Xe.current),Xe.current=null)},400),m.current.on("play",()=>{if(S.done)return;const V=xe.current;if(!V||V.achieve)return;const je=V.max_position_sec||0;je>0&&(m.current.currentTime()||0)<1.5&&(m.current.currentTime(je),S.done=!0)}),m.current.on("seeking",()=>{if(!gt.current){const V=m.current.currentTime()||0;V>1.5&&Math.abs(V-le())>3&&(S.done=!0)}hs(m.current)});const Me=m.current.tech?.(!0)?.el?.();if(Me){const V=()=>hs(m.current);Me.addEventListener("seeking",V),Me.addEventListener("webkitbeginfullscreen",V),Me.addEventListener("webkitendfullscreen",V),as.current={el:Me,fn:V}}ms(m.current,xe.current),m.current.on("timeupdate",()=>{const V=m.current.currentTime();m.current.seeking?.()||(Rs.current=V),Ne(),Wn(V)}),m.current.on("pause",()=>{const V=m.current.currentTime(),je=V-J.current;je>0&&(I.updateVideoProgress(n,l,V,je,h).then(_e=>jt(_e)).catch(_e=>console.error("Failed to update progress:",_e)),J.current=V)}),m.current.on("ended",()=>{const V=m.current.duration(),je=V-J.current,_e=()=>{if(ls(),Ws.current){const Ae=Fs.current?.();Ae&&u(Ae)}};je>0?(I.updateVideoProgress(n,l,V,je,h).then(Ae=>{jt(Ae),_e()}).catch(Ae=>{console.error("Failed to update final progress:",Ae),_e()}),J.current=V):_e()})}else{let S=s.uri||s.orig_uri;if(!(s.video_type==="cdn")){const ie=(s.encoded_uri||s.uri||s.video_id||"").match(/upload_[^/.\s]+/);ie&&(S=`/api/lms/video/stream/${ie[0]}/manifest.mpd`)}const Ne=(()=>{const E=xe.current||p;if(!E)return 0;const ie=E.achieve?E.last_position_sec||E.max_position_sec||0:E.max_position_sec||0;return ie>2?Math.floor(ie):0})();m.current=Us(R.current,{controls:!0,autoplay:!1,preload:"auto",fluid:!0,playbackRates:[.5,.75,1,1.25,1.5,1.75,2],controlBar:{pictureInPictureToggle:!0,children:["playToggle","volumePanel","currentTimeDisplay","timeDivider","durationDisplay","progressControl","remainingTimeDisplay","playbackRateMenuButton","pictureInPictureToggle","fullscreenToggle"]},sources:[/manifest\.mpd(\?.*)?$/.test(S||"")?Vn(ki(S),Ne):Vn({src:S,type:(()=>{const E=(S||"").toLowerCase().split("?")[0];
12return E.endsWith(".mpd")?"application/dash+xml":E.endsWith(".m3u8")?"application/x-mpegURL":E.endsWith(".webm")?"video/webm":"video/mp4"})()},Ne)]}),R.current&&(R.current.disablePictureInPicture=!1);const ke={done:!1,held:0},Je=()=>{const E=xe.current;if(!E)return 0;const ie=E.achieve?E.last_position_sec||E.max_position_sec||0:E.max_position_sec||0,be=m.current?.duration?.()||0;return be>0?Math.max(0,Math.min(ie,be-1)):ie},Me=()=>{if(ke.done||!m.current||!xe.current)return;const E=Je();if(E<=0)return;const ie=m.current.tech?.(!0)?.el?.();if(ie&&ie.readyState<1||m.current.seeking?.()||Date.now()-(ns.current||0)<1500)return;const be=m.current.currentTime()||0;if(Math.abs(be-E)<1.5){ke.held+=1,ke.held>=3&&(ke.done=!0);return}gt.current=!0,ns.current=Date.now(),m.current.currentTime(E),ke.held=0,window.setTimeout(()=>{gt.current=!1},800)};m.current.ready(()=>Me()),["loadedmetadata","loadeddata","canplay","canplaythrough","play"].forEach(E=>{m.current.on(E,Me)}),Me();const V=()=>{const E=R.current,ie=E?.closest(".video-player-wrapper");!E||!ie||!E.videoWidth||!E.videoHeight||(ie.style.setProperty("--gp-video-aspect",String(E.videoWidth/E.videoHeight)),ie.style.setProperty("--gp-video-ratio",`${E.videoWidth} / ${E.videoHeight}`))};["loadedmetadata","loadeddata","canplay"].forEach(E=>{m.current.on(E,V)}),V();let je=0;Xe.current=window.setInterval(()=>{je+=1,Me(),(ke.done||je>1500)&&Xe.current&&(window.clearInterval(Xe.current),Xe.current=null)},400),m.current.on("play",()=>{if(ke.done)return;const E=xe.current;if(!E||E.achieve)return;const ie=E.max_position_sec||0;ie>0&&(m.current.currentTime()||0)<1.5&&(m.current.currentTime(ie),ke.done=!0)}),m.current.on("seeking",()=>{if(!gt.current){const E=m.current.currentTime()||0;E>1.5&&Math.abs(E-Je())>3&&(ke.done=!0)}hs(m.current)});const _e=m.current.tech?.(!0)?.el?.();if(_e){const E=()=>hs(m.current);_e.addEventListener("seeking",E),_e.addEventListener("webkitbeginfullscreen",E),_e.addEventListener("webkitendfullscreen",E),as.current={el:_e,fn:E}}const Ae=R.current,ps=()=>{const E=m.current?.currentTime()||0,ie=E-J.current;ie>0&&(I.updateVideoProgress(n,l,E,ie,h).then(be=>jt(be)).catch(be=>console.error("Failed to update progress on PiP enter:",be)),J.current=E)},Qs=()=>{const E=m.current?.currentTime()||0,ie=E-J.current;ie>0&&(I.updateVideoProgress(n,l,E,ie,h).then(be=>jt(be)).catch(be=>console.error("Failed to update progress on PiP leave:",be)),J.current=E)};Ae&&(Ae.addEventListener("enterpictureinpicture",ps),Ae.addEventListener("leavepictureinpicture",Qs)),ms(m.current,xe.current),m.current.on("timeupdate",()=>{const E=m.current.currentTime();m.current.seeking?.()||(Rs.current=E),Me(),Wn(E)}),m.current.on("pause",()=>{const E=m.current.currentTime(),ie=E-J.current;ie>0&&(I.updateVideoProgress(n,l,E,ie,h).then(be=>jt(be)).catch(be=>console.error("Failed to update progress:",be)),J.current=E)}),m.current.on("ended",()=>{const E=m.current.duration(),ie=(E||0)-J.current,be=()=>{if(ls(),Ws.current){const Fe=Fs.current?.();Fe&&u(Fe)}};ie>0?(I.updateVideoProgress(n,l,E,ie,h).then(Fe=>{jt(Fe),be()}).catch(Fe=>{console.error("Failed to update final progress:",Fe),be()}),J.current=E):be()})}return()=>{Xe.current&&(window.clearInterval(Xe.current),Xe.current=null);const S=as.current;S&&(S.el.removeEventListener("seeking",S.fn),S.el.removeEventListener("webkitbeginfullscreen",S.fn),S.el.removeEventListener("webkitendfullscreen",S.fn),as.current=null),m.current&&(m.current.dispose(),m.current=null)}},[i,Z,o]);const ei=s=>{se||(Le==="single_multiple_choice"?we([s]):Le==="multi_multiple_choice"&&(qe.includes(s)?we(qe.filter(a=>a!==s)):we([...qe,s])))},ti=async()=>{if(Le==="subjective_question"){if(!U.trim()){alert(r("videoPlayer.quiz.enterAnswerAlert","답을 입력해주세요."));return}}else if(qe.length===0){alert(r("videoPlayer.quiz.selectAnswerAlert","답을 선택해주세요."));return}sn(!0);try{const s={block_id:n,cw_uuid:l,...h?{cohort_id:h}:{},submission:{submitted_at:new Date().toISOString(),try_count:1,answer_indexes:Le!=="subjective_question"?qe:[],answer_text:Le==="subjective_question"?U:""}},a=await I.submitQuiz(s);a?.result&&Ke(a.result),Be(!0);try{await $n(await I.getBlock(n))}catch{}}catch(s){console.error("Failed to submit quiz:",s),alert(r("videoPlayer.assignment.submitFailed","제출에 실패했습니다")+": "+ds(s)),Ft()}finally{sn(!1)}},si=()=>{we([]),re(""),Be(!1),Ke(null)},Fn=async s=>{const a=s.target.files;if(!(!a||a.length===0)){if(bt.length+a.length>mt){alert(r("videoPlayer.assignment.maxFilesAlert","최대 {{count}}개까지만 업로드할 수 있습니다.",{count:mt}));return}for(let c=0;c<a.length;c++)if(a[c].size>Gt*1024*1024){alert(r("videoPlayer.assignment.fileSizeAlert",'파일 "{{name}}"이(가) 최대 용량({{size}}MB)을 초과합니다.',{name:a[c].name,size:Gt}));return}dn(!0);try{const c=new FormData;for(let D=0;D<a.length;D++)c.append("files",a[D]);const f=await fetch("/api/cms/upload_files",{method:"POST",headers:{Authorization:`Bearer ${localStorage.getItem("access_token")}`},body:c});if(!f.ok)throw new Error(r("videoPlayer.assignment.uploadFailed","파일 업로드에 실패했습니다."));const P=(await f.json()).map(D=>({file_id:`file_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,original_name:D.filename,file_url:D.file_path,file_size:D.file_size,mime_type:D.content_type}));Xt(D=>[...D,...P])}catch(c){console.error("File upload failed:",c),alert(r("videoPlayer.assignment.uploadFailed","파일 업로드에 실패했습니다."))}finally{dn(!1),_t.current&&(_t.current.value="")}}},ni=s=>{Xt(a=>a.filter(c=>c.file_id!==s))},ai=async()=>
12{if(ut==="direct_input"&&!js.trim()){alert(r("videoPlayer.assignment.enterContentAlert","내용을 입력해주세요."));return}if(ut==="uploadfile"&&bt.length===0){alert(r("videoPlayer.assignment.attachFileAlert","파일을 첨부해주세요."));return}cn(!0);try{const s=new Date,a=at?new Date(at):null,c=a?s>a:!1,f={block_id:n,cw_uuid:l,...h?{cohort_id:h}:{},submission:{submitted_at:s.toISOString(),is_late:c,text_content:ut==="direct_input"?js:"",files:ut==="uploadfile"?bt:[]},result:{is_graded:!1,score_earned:0,max_score:vs,feedback_text:"",feedback_file:null},achieve:!0,achieve_detail:{status:"submitted",achieved_at:s.toISOString()}};await I.submitAssignment(f),ys(s.toISOString()),Mt("submitted"),_s({is_graded:!1,score_earned:0,max_score:vs,feedback_text:"",feedback_file:null}),alert(c?r("videoPlayer.assignment.lateSubmission","제출 기한이 지났습니다. 지각 제출로 처리됩니다."):r("videoPlayer.assignment.submitted","과제가 제출되었습니다."))}catch(s){console.error("Failed to submit assignment:",s),alert(r("videoPlayer.assignment.submitFailed","제출에 실패했습니다")+": "+ds(s)),Ft()}finally{cn(!1)}},qn=()=>{const s=Js(),a=Kt?new Date(Kt):null,c=at?new Date(at):null;return a&&s<a?{label:r("videoPlayer.assignment.beforePeriod","제출 기간 전"),class:"period-before"}:c&&s>c?{label:r("videoPlayer.assignment.afterPeriod","제출 기간 마감"),class:"period-after"}:{label:r("videoPlayer.assignment.canSubmit","제출 가능"),class:"period-active"}};if(T)return e.jsx("div",{className:"video-modal-overlay",children:e.jsx("div",{className:"video-modal-content",onClick:s=>s.stopPropagation(),children:e.jsx("div",{className:"video-modal-loading",children:e.jsx("p",{children:r("videoPlayer.loading","{{type}}을(를) 불러오는 중...",{type:Tt(o)})})})})});if(F||!i)return e.jsx("div",{className:"video-modal-overlay",children:e.jsx("div",{className:"video-modal-content",onClick:s=>s.stopPropagation(),children:e.jsxs("div",{className:"video-modal-error",children:[e.jsx("p",{children:F||r("videoPlayer.blockNotFound","블록을 찾을 수 없습니다.")}),e.jsx("button",{onClick:d,className:"btn-close-error",children:r("videoPlayer.close","닫기")})]})})});const He=i?.block_data?.content?.video,On=i?.block_data?.content?.title||i?.title||Tt(o),dt=Aa(),ii=Le==="subjective_question"||M.some(s=>s.text?.trim()),Hn=(()=>
12{if(!He)return!1;if(He.video_type==="youtube"&&He.uri||He.video_type==="cdn"&&He.uri)return!0;if(ft&&ft.status!=="completed")return!1;if(He.video_encoded===!0)return!0;const s=He.encoded_uri||He.uri||"";return/upload_[^/.\s]+/.test(s)})();return e.jsxs("div",{className:"video-modal-overlay",children:[e.jsxs("div",{className:`video-modal-content ${q?"sidebar-open":""}`,onClick:s=>s.stopPropagation(),children:[e.jsxs("div",{className:"video-modal-header",children:[e.jsxs("div",{className:"video-modal-header-left",children:[e.jsx("button",{className:"hamburger-menu-btn",onClick:()=>H(!q),children:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",children:[e.jsx("line",{x1:"3",y1:"6",x2:"21",y2:"6",strokeWidth:"2",strokeLinecap:"round"}),e.jsx("line",{x1:"3",y1:"12",x2:"21",y2:"12",strokeWidth:"2",strokeLinecap:"round"}),e.jsx("line",{x1:"3",y1:"18",x2:"21",y2:"18",strokeWidth:"2",strokeLinecap:"round"})]})}),e.jsxs("div",{className:"video-modal-title-section",children:[k&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"module-title",children:Ht(k.moduleTitle)}),e.jsx("span",{className:"title-separator",children:">"}),e.jsxs("span",{className:"session-number",children:[k.sessionNumber,r("videoPlayer.session","차시"),"."]}),e.jsx("span",{className:"session-title",children:Ht(k.sessionTitle)})]}),!k&&e.jsx("h2",{children:On})]})]}),e.jsx("div",{className:"video-modal-header-right",children:e.jsx("button",{className:"video-modal-close-btn",onClick:Oa,children:e.jsx("svg",{stroke:"currentColor",fill:"currentColor",strokeWidth:"0",viewBox:"0 0 24 24",height:"1em",width:"1em",children:e.jsx("path",{fill:"none",stroke:"#000",strokeWidth:"2",d:"M3,3 L21,21 M3,21 L21,3"})})})})]}),e.jsxs("div",{className:`syllabus-sidebar ${q?"open":""}`,children:[e.jsxs("div",{className:"syllabus-sidebar-header",children:[e.jsx("h3",{children:r("videoPlayer.learningIndex","학습목차")}),e.jsx("button",{onClick:()=>H(!1),children:"×"})]}),e.jsx("div",{className:"syllabus-sidebar-content",children:Y.map((s,a)=>e.jsxs("div",{className:"syllabus-module",children:[e.jsxs("div",{className:"syllabus-module-title",children:[s.moduleNumber,r("videoPlayer.week","주차")]}),s.sessions?.map((c,f)=>{const j=c.blocks?.[0],P=c.blocks?.some(D=>D.blockId===n);return e.jsxs("div",{className:"syllabus-session",children:[e.jsxs("div",{className:`syllabus-session-title ${P?"active":""}`,onClick:()=>j&&St(j.blockId,j.blockType),style:{cursor:j?"pointer":"default"},children:[c.sessionNumber,r("videoPlayer.session","차시"),". ",Ht(c.sessionTitle),(()=>{const D=(c.blocks||[]).filter(le=>["video","quiz","assignment","exam"].includes((le.blockType||"").toLowerCase()));if(!D.length)return null;const S=D.filter(le=>Is(le.blockId)).length;return e.jsxs("span",{className:`syllabus-session-progress ${S===D.length?"done":""}`,children:[S,"/",D.length]})})()]}),c.blocks?.map((D,S)=>e.jsxs("div",{className:`syllabus-block ${D.blockId===n?"active":""}`,onClick:()=>St(D.blockId,D.blockType),style:{cursor:"pointer"},children:[e.jsx("img",{alt:Tt(D.blockType),className:"block-icon",src:us(D.blockType),style:{width:"20px",height:"20px",marginRight:"8px",display:"inline-block",verticalAlign:"middle"}}),e.jsx("span",{style:{verticalAlign:"middle"},children:D.title||Tt(D.blockType)}),(()=>{const le=Ln(D.blockId);return le===null?null:Is(D.blockId)?e.jsx("span",{className:"syllabus-block-progress done",title:"완료",children:"✓"}):e.jsxs("span",{className:"syllabus-block-progress",children:[le,"%"]})})()]},S))]},f)})]},a))})]}),e.jsxs("div",{className:`video-modal-body ${T?"loading-no-scroll":""}`,ref:Ie,children:[lt&&lt.open===!1&&e.jsxs("div",{className:"review-only-banner",role:"status",children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("line",{x1:"12",y1:"8",x2:"12",y2:"12"}),e.jsx("line",{x1:"12",y1:"16",x2:"12.01",y2:"16"})]}),e.jsxs("span",{children:[e.jsx("b",{children:lt.state==="before"?"아직 학습 기간이 아닙니다.":"복습만 가능합니다."})," ",lt.message]})]}),!Wt&&o==="video"&&(fn||Vs)&&e.jsxs("div",{className:"review-only-banner",role:"status",children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("line",{x1:"12",y1:"8",x2:"12",y2:"12"}),e.jsx("line",{x1:"12",y1:"16",x2:"12.01",y2:"16"})]}),e.jsxs("span",{children:[e.jsx("b",{children:"진도로 인정되지 않습니다."})," ",fn||(ct.state==="before"?`학습 인정 기간(${Et(ct)}) 전입니다. 지금 시청한 것은 기록되지만 진도로 인정되지 않습니다.`:`학습 인정 기간(${Et(ct)})이 끝났습니다. 지금 시청한 것은 기록되지만 진도로 인정되지 않습니다.`)]})]}),e.jsxs("div",{className:`video-content-wrapper${Mn?" is-material":""}`,children:[e.jsxs("div",{className:"video-section",children:[o==="video"&&!Hn&&e.jsx("div",{style:{aspectRatio:"16 / 9",width:"100%",background:"#1a1a1a",color:"#fff",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:8,flexDirection:"column",gap:12},children:ft?.status==="failed"?e.jsxs(e.Fragment,{children:[e.jsxs("svg",{width:"56",height:"56",viewBox:"0 0 24 24",fill:"none",stroke:"#f87171",strokeWidth:"1.5",children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("line",{x1:"12",y1:"7",x2:"12",y2:"13"}),e.jsx("line",{x1:"12",y1:"16.5",x2:"12",y2:"16.6"})]}),e.jsx("div",{style:{fontSize:18,fontWeight:500},children:"영상 변환에 실패했습니다"}),e.jsxs("div",{style:{fontSize:13,opacity:.75,textAlign:"center",lineHeight:1.6},children:["담당 교수님께 다시 올려 달라고 알려 주세요.",e.jsx("br",{}),"이 차시는 잠시 뒤에도 재생되지 않습니다."]})]}):ft?e.jsxs(e.Fragment,{children:[e.jsx("svg",{width:"52",height:"52",viewBox:"0 0 24 24",fill:"none",stroke:"#93c5fd",strokeWidth:"2",strokeLinecap:"round",className:"animate-spin",style:{animationDuration:"1.6s"},children:e.jsx("path",{d:"M21 12a9 9 0 1 1-6.2-8.56"})}),e.jsx("div",{style:{fontSize:18,fontWeight:500},children:"영상을 변환하고 있습니다"}),e.jsxs("div",{style:{width:"min(320px, 70%)"},children:[e.jsx("div",{style:{height:6,borderRadius:3,background:"rgba(255,255,255,0.18)",overflow:"hidden"},children:e.jsx("div",{style:{width:`${Math.max(3,Math.min(100,ft.progress||0))}%`,height:"100%",background:"#60a5fa",borderRadius:3,transition:"width .4s ease"}})}),e.jsx("div",{style:{marginTop:7,fontSize:12.5,opacity:.8,textAlign:"center"},children:ft.progress?`${ft.progress}% 진행`:"차례를 기다리는 중"})]}),e.jsxs("div",{style:{fontSize:13,opacity:.7,textAlign:"center",lineHeight:1.6},children:["올린 영상을 재생할 수 있는 형식으로 바꾸는 중입니다.",e.jsx("br",{}),e.jsx("b",{style:{fontWeight:600},children:"끝나면 이 화면이 저절로 재생 화면으로 바뀝니다."}
12)," 잠시 뒤 다시 오셔도 됩니다."]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("svg",{width:"56",height:"56",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",style:{opacity:.7},children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("polyline",{points:"12 6 12 12 16 14"})]}),e.jsx("div",{style:{fontSize:18,fontWeight:500},children:"동영상 파일 준비중입니다"}),e.jsx("div",{style:{fontSize:13,opacity:.7},children:"업로드 또는 인코딩이 완료되면 재생할 수 있습니다."})]})}),o==="video"&&He&&Hn&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:`video-transcript-container ${xt&&We.length>0&&$t==="panel"?"with-transcript":""}`,children:[e.jsxs("div",{className:"video-player-wrapper",children:[e.jsx("div",{"data-vjs-player":!0,children:e.jsx("video",{ref:R,className:"video-js vjs-default-skin vjs-big-play-centered",playsInline:!0,"webkit-playsinline":"true","x-webkit-airplay":"deny"})}),e.jsx(Ui,{}),We.length>0&&xt&&$t==="overlay"&&vt>=0&&e.jsx("div",{className:"transcript-overlay",children:e.jsx("span",{className:"transcript-overlay-text",children:We[vt]?.text})}),(We.length>0||i?.block_data?.content?.video?.video_type!=="youtube")&&e.jsxs("div",{className:"transcript-control-container",ref:$s,children:[We.length>0&&e.jsx("button",{className:`transcript-control-btn ${xt?"active":""}`,onClick:()=>zt(!is),title:r("videoPlayer.transcript","스크립트"),children:e.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M7 8h10M7 12h6"})]})}),i?.block_data?.content?.video?.video_type!=="youtube"&&e.jsx("button",{className:"transcript-control-btn pip-control-btn",onClick:async()=>{try{document.pictureInPictureElement?await document.exitPictureInPicture():R.current&&await R.current.requestPictureInPicture()}catch(s){console.error("PiP error:",s)}},title:r("videoPlayer.pip","PiP 모드"),children:e.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2"}),e.jsx("rect",{x:"11",y:"9",width:"9",height:"6",rx:"1",fill:"currentColor"})]})}),is&&We.length>0&&e.jsxs("div",{className:"transcript-menu",children:[e.jsx("div",{className:"transcript-menu-header",children:r("videoPlayer.transcript","스크립트")}),e.jsxs("button",{className:`transcript-menu-item ${xt&&$t==="panel"?"active":""}`,onClick:()=>{Nn("panel"),ss(!0),zt(!1)},children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"}),e.jsx("line",{x1:"9",y1:"3",x2:"9",y2:"21"})]}),r("videoPlayer.transcriptPanelMode","별도창")]}),e.jsxs("button",{className:`transcript-menu-item ${xt&&$t==="overlay"?"active":""}`,onClick:()=>{Nn("overlay"),ss(!0),zt(!1)},children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2",ry:"2"}),e.jsx("line",{x1:"8",y1:"21",x2:"16",y2:"21"}),e.jsx("line",{x1:"12",y1:"17",x2:"12",y2:"21"})]}),r("videoPlayer.transcriptOverlayMode","화면위 오버레이")]}),e.jsxs("button",{className:`transcript-menu-item ${xt?"":"active"}`,onClick:()=>{ss(!1),zt(!1)},children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),e.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]}),r("videoPlayer.hideTranscript","숨기기")]})]})]})]}),(We.length>0&&xt&&$t==="panel"||Dt.length>0)&&e.jsxs("div",{className:`transcript-panel ${kt==="materials"?"materials-active":""}`,ref:Ea,children:[e.jsxs("div",{className:"transcript-header",children:[We.length>0&&Dt.length>0?e.jsxs("div",{className:"panel-tabs",children:[e.jsxs("button",{className:`panel-tab ${kt==="transcript"?"active":""}`,onClick:()=>Cn("transcript"),children:[e.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:e.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})}),r("videoPlayer.transcript","스크립트")]}),e.jsxs("button",{className:`panel-tab ${kt==="materials"?"active":""}`,onClick:()=>Cn("materials"),children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"})]}),r("videoPlayer.materials","참고자료"),e.jsx("span",{className:"panel-tab-badge",children:Dt.length})]})]}):We.length>0?e.jsxs("span",{className:"transcript-title",children:[e.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:e.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})}),r("videoPlayer.transcript","스크립트")]}):e.jsxs("span",{className:"transcript-title",children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"}),e.jsx("polyline",{points:"14,2 14,8 20,8"})]}),r("videoPlayer.materials","참고자료")]}),e.jsxs("div",{className:"transcript-header-actions",children:[kt==="transcript"&&wt.length>=1&&e.jsx("span",{className:"transcript-language-indicator",children:wt.length>1?e.jsx("select",{className:"transcript-language-select",value:Pa,onChange:s=>Va(s.target.value),title:r("videoPlayer.selectLanguage","언어 선택"),children:wt.map(s=>e.jsx("option",{value:s.lang,children:s.label},s.lang))}):e.jsx("span",{className:"transcript-language-label",children:wt[0]?.label})}),e.jsx("button",{className:"transcript-close-btn",onClick:()=>ss(!1),title:r("videoPlayer.hideTranscript","패널 숨기기"),children:"×"})]})]}),kt==="transcript"&&We.length>0&&e.jsx("div",{className:"transcript-body",ref:rs,onMouseEnter:Gs,onMouseLeave:Ks,onTouchStart:Gs,onTouchEnd:Ks,onScroll:Gs,children:We.map((s,a)=>{const c=p?.achieve===!0,f=p?.max_position_sec||0,j=c||s.startTime<=f;return e.jsxs("div",{className:`transcript-line ${a===vt?"active":""} ${j?"":"disabled"}`,onClick:()=>{j&&(m.current&&m.current.currentTime(s.startTime),Ks())},title:j?"":r("videoPlayer.transcriptLocked","해당 구간까지 학습을 완료해야 이동할 수 있습니다"),children:[e.jsxs("span",{className:"transcript-timestamp",children:[Math.floor(s.startTime/60),":",Math.floor(s.startTime%60).toString().padStart(2,"0")]}),e.jsx("span",{className:"transcript-text",children:s.text}),!j&&e.jsx("span",{className:"transcript-lock",children:e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"3",y:"11",width:"18",height:"11",rx:"2",ry:"2"}),e.jsx("path",{d:"M7 11V7a5 5 0 0 1 10 0v4"})]})})]},s.id)})}),Dt.length>0&&e.jsx("div",{className:"transcript-body materials-body",style:{display:kt==="materials"?"flex":"none"},children:e.jsx(Kn,{attachments:Dt,blockId:n,videoId:i?.block_data?.content?.video?.video_id||""})})]})]}),e.jsxs("div",{className:"video-info",children:[e.jsxs("div",{className:"video-info-left",children:[e.jsxs("div",{className:"video-info-item",children:[e.jsxs("span",{className:"label",children:[r("videoPlayer.studyTime","학습시간"),":"]}),e.jsx("span",{className:"value",children:p&&p.video_duration_sec>0?`${Ds(p.max_position_sec||0)} / ${Ds(p.video_duration_sec)}`:He?.video_length?`0:00 / ${Ds(He.video_length)}`:"-"})]}),p&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"video-info-item",children:[e.jsxs("span",{className:"label",children:[r("videoPlayer.currentProgress","현재 진도율"),":"]}),e.jsxs("span",{className:`value ${p.achieve?"achieved":""}`,children:[Math.round(Number(p.progress_percent??0)),"%"]})]}),e.jsxs("div",{className:"video-info-item",children:[e.jsxs("span",{className:"label",children:[r("videoPlayer.requiredProgress","학습인정진도율"),":"]}),e.jsxs("span",{className:"value",children:[p.required_percent!==void 0&&p.required_percent!==null?p.required_percent:i?.block_data?.content?.minimum_progress??80,"% ",r("videoPlayer.above","이상")]})]})]}),(()=>{const s=xs(i?.block_data?.content);return s.active?e.jsxs("div",{className:`video-info-item vi-period vi-period-${s.state}`,title:en(s),children:[e.jsx("span",{className:"label",children:"학습 인정 기간:"}),e.jsxs("span",{className:"value",children:[Et(s),e.jsx("em",{children:sa(s)})]})]}):null})()]}),e.jsx("div",{className:"video-info-right",children:e.jsx("div",{className:"status-badge",style:{backgroundColor:dt.color},children:dt.status})})]})]}),o==="quiz"&&e.jsx("div",{className:"quiz-content-section",children:ii?e.jsxs("div",{className:"quiz-learner-content",children:[e.jsxs("div",{className:"quiz-header",children:[e.jsx("h3",{className:"quiz-title",children:Re||r("videoPlayer.quiz.noTitle","제목 없음")}),nt&&e.jsx("div",{className:"quiz-description",dangerouslySetInnerHTML:{__html:nt}}),e.jsxs("div",{className:"quiz-meta",children:[e.jsxs("span",{className:"quiz-badge quiz-badge-score",children:[r("videoPlayer.quiz.score","배점"),": ",L,r("videoPlayer.quiz.points","점")]}),e.jsxs("span",{className:"quiz-badge quiz-badge-type",children:[Le==="single_multiple_choice"&&r("videoPlayer.quiz.singleChoice","객관식 단답형"),Le==="multi_multiple_choice"&&r("videoPlayer.quiz.multipleChoice","객관식 복수형"),Le==="subjective_question"&&r("videoPlayer.quiz.subjective","주관식")]}),e.jsx("div",{className:"status-badge",style:{backgroundColor:dt.color,marginLeft:"auto"},children:dt.status})]})]}),e.jsx("div",{className:"quiz-body",children:Le==="subjective_question"?e.jsx("div",{className:"subjective-answer-area",children:e.jsx("textarea",{value:U,onChange:s=>re(s.target.value),placeholder:r("videoPlayer.quiz.enterAnswer","답을 입력하세요"),disabled:se,rows:4,className:"quiz-textarea"})}):e.jsx("div",{className:"quiz-options",children:M.map((s,a)=>({opt:s,originalIndex:a})).filter(({opt:s})=>s.text?.trim()).map(({opt:s,originalIndex:a})=>{const c=qe.includes(a),f=se&&c,j=s.is_correct;return e.jsxs("div",{className:`quiz-option ${c?se?j?"correct":"incorrect":"selected":se&&j?"correct-answer":""}`,onClick:()=>ei(a),children:[e.jsxs("div",{className:"quiz-option-content",children:[e.jsx("div",{className:"quiz-option-indicator",children:Le==="single_multiple_choice"?e.jsx("div",{className:`radio-indicator ${c?"selected":""}`,children:c&&e.jsx("div",{className:"radio-dot"})}):e.jsx("div",{className:`checkbox-indicator ${c?"selected":""}`,children:c&&e.jsx("span",{className:"checkbox-check",children:e.jsx(ce,{name:"check",size:12,strokeWidth:3})})})}),e.jsxs("div",{className:"quiz-option-text",children:[e.jsxs("span",{className:"option-number",children:[a+1,"."]}
12),e.jsx("span",{children:s.text}),se&&j&&e.jsxs("span",{className:"correct-marker",children:[e.jsx(ce,{name:"check",size:13})," ",r("videoPlayer.quiz.correctAnswer","정답")]})]})]}),f&&s.feedback&&e.jsx("div",{className:"quiz-option-feedback",children:s.feedback})]},s.id)})})}),se&&ze&&e.jsxs("div",{className:`quiz-result ${ze.is_correct?"correct":"incorrect"}`,children:[e.jsxs("div",{className:"quiz-result-header",children:[e.jsx("span",{className:"quiz-result-icon",children:e.jsx(ce,{name:ze.is_correct?"check":"close",size:26,strokeWidth:2.5})}),e.jsx("span",{className:"quiz-result-text",children:ze.is_correct?r("videoPlayer.quiz.yourAnswer","정답입니다!"):r("videoPlayer.quiz.wrongAnswer","오답입니다.")}),e.jsxs("span",{className:"quiz-result-score",children:[r("videoPlayer.quiz.earnedScore","획득 점수"),": ",ze.score_earned," / ",ze.max_score,r("videoPlayer.quiz.points","점")]})]}),(ze.is_correct?x:te)&&e.jsx("div",{className:"quiz-result-feedback",children:ze.is_correct?x:te})]}),e.jsx("div",{className:"quiz-actions",children:se?e.jsx("button",{className:"quiz-reset-btn",onClick:si,children:r("videoPlayer.quiz.tryAgain","다시 풀기")}):e.jsx("button",{className:"quiz-submit-btn",onClick:ti,disabled:Rt||ot,title:os,children:ot?cs:Rt?r("videoPlayer.quiz.submitting","제출 중..."):r("videoPlayer.quiz.submitAnswer","답안 제출")})})]}):e.jsx("div",{className:"quiz-no-content",children:e.jsx("p",{children:r("videoPlayer.quiz.noQuiz","등록된 퀴즈가 없습니다.")})})}),o==="assignment"&&e.jsx("div",{className:"assignment-content-section",children:e.jsxs("div",{className:"assignment-learner-content",children:[e.jsxs("div",{className:"assignment-header",children:[e.jsx("h3",{className:"assignment-title",children:ca||"제목 없음"}),nn&&e.jsx("div",{className:"assignment-description",dangerouslySetInnerHTML:{__html:nn}})]}),e.jsxs("div",{className:"assignment-info-grid",children:[e.jsxs("div",{className:"assignment-info-item",children:[e.jsx("span",{className:"info-label",children:"배점"}),e.jsxs("span",{className:"info-value",children:[vs,"점"]})]}),e.jsxs("div",{className:"assignment-info-item",children:[e.jsx("span",{className:"info-label",children:"제출 방식"}),e.jsx("span",{className:"info-value",children:ut==="direct_input"?"직접 작성":"파일 업로드"})]}),ut==="uploadfile"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"assignment-info-item",children:[e.jsx("span",{className:"info-label",children:"파일 수"}),e.jsxs("span",{className:"info-value",children:["최대 ",mt,"개"]})]}),e.jsxs("div",{className:"assignment-info-item",children:[e.jsx("span",{className:"info-label",children:"파일 용량"}),e.jsxs("span",{className:"info-value",children:["최대 ",Gt,"MB"]})]})]}),e.jsxs("div",{className:"assignment-info-item",children:[e.jsx("span",{className:"info-label",children:"상태"}),e.jsx("div",{className:"status-badge",style:{backgroundColor:dt.color},children:dt.status})]})]}),an.length>0&&e.jsxs("div",{className:"assignment-instructor-files",children:[e.jsx("h4",{className:"section-title",children:"첨부 자료"}),e.jsx("div",{className:"instructor-files-list",children:an.map((s,a)=>e.jsxs("div",{className:"instructor-file-item",children:[e.jsx("span",{className:"file-icon",children:e.jsx(ce,{name:"file",size:16})}),e.jsx("a",{href:s.file_url,target:"_blank",rel:"noopener noreferrer",className:"file-link",download:s.file_name,children:s.file_name}),s.file_size&&e.jsxs("span",{className:"file-size",children:["(",(s.file_size/1024).toFixed(1)," KB)"]})]},a))})]}),e.jsxs("div",{className:"assignment-period",children:[e.jsx("h4",{className:"section-title",children:"제출 기간"}),e.jsxs("div",{className:"period-info",children:[e.jsxs("div",{className:"period-row",children:[e.jsx("span",{className:"period-label",children:"시작:"}),e.jsx("span",{className:"period-value",children:Kt?new Date(Kt).toLocaleString("ko-KR"):"-"})]}),e.jsxs("div",{className:"period-row",children:[e.jsx("span",{className:"period-label",children:"마감:"}),e.jsx("span",{className:"period-value deadline",children:at?new Date(at).toLocaleStr
12ing("ko-KR"):"-"})]})]}),e.jsx("div",{className:`period-status ${qn().class}`,children:qn().label})]}),Qt==="none"&&e.jsxs("div",{className:"assignment-submission",children:[e.jsx("h4",{className:"section-title",children:"과제 제출"}),ut==="direct_input"?e.jsx("textarea",{value:js,onChange:s=>bs(s.target.value),placeholder:"과제 내용을 입력하세요...",rows:6,className:"submission-textarea"}):e.jsx("div",{className:"submission-upload",children:bt.length===0?e.jsxs("div",{className:"upload-dropzone",onClick:()=>_t.current?.click(),children:[e.jsx("input",{ref:_t,type:"file",multiple:mt>1,onChange:Fn,className:"hidden-input"}),e.jsx("div",{className:"dropzone-icon",children:e.jsx(ce,{name:"folder-open",size:34})}),e.jsx("p",{className:"dropzone-text",children:"클릭하여 파일을 선택하거나"}),e.jsx("p",{className:"dropzone-text",children:"파일을 여기에 드래그하세요"}),e.jsxs("p",{className:"dropzone-hint",children:["최대 ",mt,"개, 각 ",Gt,"MB 이하"]})]}):e.jsxs("div",{className:"uploaded-files",children:[bt.map((s,a)=>e.jsxs("div",{className:"uploaded-file-item",children:[e.jsxs("div",{className:"file-info",children:[e.jsx("span",{className:"file-icon",children:e.jsx(ce,{name:"file",size:16})}),e.jsx("span",{className:"file-name",children:s.original_name}),e.jsxs("span",{className:"file-size",children:["(",(s.file_size/1024).toFixed(1)," KB)"]})]}),e.jsx("button",{className:"remove-file-btn",onClick:()=>ni(s.file_id),children:"×"})]},a)),bt.length<mt&&e.jsx("button",{className:"add-more-files-btn",onClick:()=>_t.current?.click(),children:"+ 파일 추가"}),e.jsx("input",{ref:_t,type:"file",multiple:mt>1,onChange:Fn,className:"hidden-input"})]})}),e.jsx("button",{className:"submit-btn",onClick:ai,disabled:ln||on||ot,title:os,children:ot?cs:ln?"제출 중...":on?"업로드 중...":"제출하기"})]}),Qt==="submitted"&&!yt?.is_graded&&e.jsxs("div",{className:"submission-complete",children:[e.jsx("div",{className:"complete-icon",children:e.jsx(ce,{name:"check",size:30,strokeWidth:2.6})}),e.jsx("p",{className:"complete-title",children:"과제가 제출되었습니다."}),e.jsx("p",{className:"complete-subtitle",children:"교수자의 채점을 기다리고 있습니다."}),rn&&e.jsxs("p",{className:"submitted-at",children:["제출 일시: ",Lt(rn)?.toLocaleString("ko-KR",{timeZone:"Asia/Seoul"})]}),(!at||new Date<=new Date(at))&&e.jsx("button",{className:"submit-btn",style:{marginTop:"16px"},onClick:()=>Mt("none"),children:"수정하기"})]}),Qt==="graded"&&yt?.is_graded&&e.jsxs("div",{className:"grading-result",children:[e.jsx("h4",{className:"section-title",children:"채점 결과"}),e.jsxs("div",{className:"score-display",children:[e.jsx("span",{className:"score-earned",children:yt.score_earned}),e.jsx("span",{className:"score-divider",children:"/"}),e.jsxs("span",{className:"score-max",children:[yt.max_score,"점"]})]}),yt.feedback_text&&e.jsxs("div",{className:"feedback-box",children:[e.jsx("h5",{className:"feedback-title",children:"교수 피드백"}),e.jsx("p",{className:"feedback-content",children:yt.feedback_text})]})]})]})}),o==="exam"&&e.jsx("div",{className:"exam-content-section",children:va?e.jsxs("div",{className:"exam-taking-container",children:[e.jsxs("div",{className:"exam-taking-header",children:[e.jsx("div",{className:"exam-taking-title",children:i?.title||"시험"}),e.jsxs("div",{className:"exam-taking-info",children:[e.jsxs("span",{className:"exam-progress",children:[ne+1," / ",fe.length," 문항"]}),Ts!==null&&e.jsxs("span",{className:`exam-timer ${Ts<60?"warning":""}`,children:[e.jsx(ce,{name:"clock",size:14})," ",Ua(Ts)]})]})]}),e.jsx("div",{className:"exam-question-nav",children:fe.map((s,a)=>{const c=At[a]?.length>0||Zt[a]?.trim(),f=Ue&&Qe?.results?.[a]?.is_correct,j=Ue&&Qe?.results?.[a]&&!Qe.results?.[a]?.is_correct;return e.jsx("button",{className:`exam-nav-btn ${a===ne?"active":""} ${c?"answered":""} ${f?"correct":""} ${j?"wrong":""}`,onClick:()=>Yt(a),children:a+1},a)})}),fe[ne]&&e.jsxs("div",{className:"exam-question-content",children:[e.jsxs("div",{className:"exam-question-header",children:[e.jsxs("span",{className:"question-number",children:["문제 ",ne+1]}),e.jsxs("span",{className:"question-score",children:["(",fe[ne].allocated_score,"점)"]}),e.jsxs("span",{className:"question-type",children:[fe[ne].type==="single_choice"&&"객관식 단답형",(fe[ne].type==="multi_choice"||fe[ne].type==="multiple_choice")&&"객관식 복수형",(fe[ne].type==="short_answer"||fe[ne].type==="subjective")&&"주관식",fe[ne].type==="long_answer"&&"서술형"]})]}),e.jsx("div",{className:"exam-question-title",children:fe[ne].title}),fe[ne].description&&e.jsx("div",{className:"exam-question-description",dangerouslySetInnerHTML:{__html:fe[ne].description}}),fe[ne].type==="short_answer"||fe[ne].type==="subjective"||fe[ne].type==="long_answer"?e.jsx("div",{className:"exam-text-answer",children:e.jsx("textarea",{value:Zt[ne]||"",onChange:s=>Ja(ne,s.target.value),placeholder:"답을 입력하세요",disabled:Ue,rows:fe[ne].type==="long_answer"?8:4,className:"exam-textarea"})}):e.jsx("div",{className:"exam-options",children:fe[ne].options.filter(s=>s.text?.trim()).map((s,a)=>{const c=(At[ne]||[]).includes(a),f=s.is_correct,j=Ue&&i?.block_data?.content?.disclosure_settings?.show_grade,P=fe[ne].type==="multi_choice"||fe[ne].type==="multiple_choice";return e.jsxs("div",{className:`exam-option ${c?"selected":""} ${j&&c?f?"correct":"incorrect":""} ${j&&f&&!c?"correct-answer":""}`,onClick:()=>Ya(ne,a,P),children:[e.jsx("div",{className:"exam-option-indicator",children:P?e.jsx("div",{className:`checkbox-indicator ${c?"selected":""}`,children:c&&e.jsx("span",{children:e.jsx(ce,{name:"check",size:12,strokeWidth:3})})}):e.jsx("div",{className:`radio-indicator ${c?"selected":""}`,children:c&&e.jsx("div",{className:"radio-dot"})})}),e.jsxs("div",{className:"exam-option-text",children:[e.jsxs("span",{className:"option-number",children:[a+1,"."]}
12),e.jsx("span",{children:s.text}),j&&f&&e.jsxs("span",{className:"correct-marker",children:[e.jsx(ce,{name:"check",size:13})," 정답"]})]})]},a)})}),Ue&&Qe?.results?.[ne]&&e.jsxs("div",{className:`exam-question-result ${Qe.results?.[ne]?.is_correct?"correct":"incorrect"}`,children:[e.jsx("span",{className:"result-icon",children:e.jsx(ce,{name:Qe.results?.[ne]?.is_correct?"check":"close",size:24,strokeWidth:2.5})}),e.jsx("span",{className:"result-text",children:Qe.results?.[ne]?.is_correct?"정답":"오답"}),e.jsxs("span",{className:"result-score",children:[Qe.results?.[ne]?.score_earned," / ",Qe.results?.[ne]?.max_score,"점"]})]})]}),e.jsxs("div",{className:"exam-taking-footer",children:[e.jsxs("div",{className:"exam-nav-buttons",children:[e.jsxs("button",{className:"exam-prev-btn",onClick:()=>Yt(Math.max(0,ne-1)),disabled:ne===0,children:[e.jsx(ce,{name:"prev",size:12})," 이전"]}),e.jsxs("button",{className:"exam-next-btn",onClick:()=>Yt(Math.min(fe.length-1,ne+1)),disabled:ne===fe.length-1,children:["다음 ",e.jsx(ce,{name:"next",size:12})]})]}),Ue?e.jsxs("div",{className:"exam-final-result",children:[e.jsx("span",{className:"final-score-label",children:"최종 점수:"}),e.jsxs("span",{className:"final-score-value",children:[Qe?.earned_score," / ",Qe?.total_score,"점"]})]}):e.jsx("button",{className:"exam-submit-btn",onClick:()=>Dn(),disabled:Cs||ot,title:os,children:ot?cs:Cs?"제출 중...":"시험 제출"})]})]}):e.jsxs("div",{className:"exam-info-container",children:[e.jsx("div",{className:"exam-icon-wrapper",children:e.jsx("img",{src:"/lmsicons/todo/목록/시험.svg",alt:"시험",className:"exam-icon-large"})}),e.jsx("h3",{className:"exam-title",children:i?.title||i?.block_data?.content?.title||"시험"}),i?.block_data?.content?.description&&e.jsx("p",{className:"exam-description",children:i.block_data.content.description}),e.jsxs("div",{className:"exam-notice",children:[e.jsx("div",{className:"exam-notice-icon",children:e.jsx(ce,{name:"clipboard",size:30})}),e.jsxs("div",{className:"exam-notice-text",children:[e.jsx("p",{className:"exam-notice-title",children:"시험 응시 안내"}),e.jsx("p",{className:"exam-notice-desc",children:"시험 시작 후에는 중간에 나갈 수 없으므로, 안정적인 환경에서 응시하세요."}),e.jsx("p",{className:"exam-notice-desc",children:"모든 문항에 답변 후 제출 버튼을 클릭하세요."})]})]}),i?.block_data?.content?.time_limit?.active&&e.jsxs("div",{className:"exam-time-limit",children:[e.jsx("span",{className:"time-icon",children:e.jsx(ce,{name:"clock",size:15})}),e.jsxs("span",{children:["제한 시간: ",i.block_data.content.time_limit.duration?.hours||0,"시간 ",i.block_data.content.time_limit.duration?.minutes||0,"분"]})]}),e.jsxs("div",{className:"exam-meta",children:[e.jsxs("div",{className:"exam-meta-item",children:[e.jsx("span",{className:"meta-label",children:"문항 수"}),e.jsxs("span",{className:"meta-value",children:[fe.length,"문항"]})]}),e.jsxs("div",{className:"exam-meta-item",children:[e.jsx("span",{className:"meta-label",children:"총점"}),e.jsxs("span",{className:"meta-value",children:[fe.reduce((s,a)=>s+a.allocated_score,0),"점"]})]})]}),e.jsx("button",{className:"exam-start-btn",onClick:Za,disabled:Es||ot||qt,title:qt?`응시 시간: ${An}`:os,children:ot?cs.replace("제출","응시"):qt?"응시 시간 종료":Es?"시작하는 중...":ht?.state==="running"?"이어서 응시하기":"시험 응시하기"}),qt&&e.jsxs("p",{className:"exam-notice-desc",role:"status",style:{marginTop:8,color:"#b45309"},children:["응시 시간(",An,")이 끝났습니다. 제한시간 시험은 처음 시작한 때부터 한 번만 응시할 수 있습니다."]}),ht?.state==="running"&&!qt&&e.jsxs("p",{className:"exam-notice-desc",role:"status",style:{marginTop:8},children:["진행 중인 응시가 있습니다 (마감 ",Vt(ht.deadline),"). 제한시간은 처음 시작한 때부터 계산됩니다."]})]})}),o==="attendance"&&e.jsx("div",{className:"attendance-content-section",children:e.jsxs("div",{className:"attendance-container",children:[e.jsxs("div",{className:"attendance-header",children:[e.jsx("h3",{className:"attendance-title",children:_a||"출석"}),es&&e.jsxs("div",{className:"attendance-session-info",children:[e.jsx("span",{className:"session-date",children:es.date}),e.jsxs("span",{className:"session-time",children:[es.start_time," ~ ",es.end_time]})]}),e.jsxs("div",{className:"attendance-badges",children:[e.jsx("span",{className:`attendance-badge ${Nt==="instructor_managed"?"managed":"checkin"}
12`,children:Nt==="instructor_managed"?"교수자 관리":"학습자 직접 출석"}),Nt==="student_checkin"&&pt&&e.jsx("span",{className:"attendance-badge gps",children:"GPS 인증"}),e.jsx("div",{className:"status-badge",style:{backgroundColor:dt.color,marginLeft:"auto"},children:dt.status})]})]}),e.jsxs("div",{className:"attendance-body",children:[he&&e.jsxs("div",{className:"attendance-managed-message",children:[e.jsx("div",{className:"managed-icon",children:e.jsx(ce,{name:"clipboard",size:28})}),e.jsxs("p",{children:["수강생 출석은 ",e.jsx("b",{children:"학습 관리"}),"에서 처리합니다."]}),e.jsx("p",{className:"sub-message",children:"이 화면은 학습자에게 보이는 모습입니다. 선생님 계정에는 출석 기록이 없습니다."})]}),!he&&Se?.status&&e.jsxs("div",{className:`attendance-result ${Se.status.toLowerCase()}`,children:[e.jsxs("div",{className:"result-icon",children:[Se.status==="PRESENT"&&e.jsx(ce,{name:"check",size:16}),Se.status==="LATE"&&e.jsx(ce,{name:"clock",size:16}),Se.status==="ABSENT"&&e.jsx(ce,{name:"close",size:16}),Se.status==="EXCUSED"&&e.jsx(ce,{name:"clipboard",size:16})]}),e.jsxs("div",{className:"result-text",children:[Se.status==="PRESENT"&&"출석",Se.status==="LATE"&&"지각",Se.status==="ABSENT"&&"결석",Se.status==="EXCUSED"&&"공결"]}),Se.checkin_time&&e.jsxs("div",{className:"checkin-time",children:["체크인: ",new Date(Se.checkin_time).toLocaleString("ko-KR")]})]}),!he&&!Se?.status&&Nt==="instructor_managed"&&e.jsxs("div",{className:"attendance-managed-message",children:[e.jsx("div",{className:"managed-icon",children:e.jsx(ce,{name:"clipboard",size:28})}),e.jsx("p",{children:"교수자/운영자가 직접 출석을 체크합니다."}),e.jsx("p",{className:"sub-message",children:"학습자는 출석 상태만 확인할 수 있습니다."})]}),!he&&!Se?.status&&Nt==="student_checkin"&&e.jsxs("div",{className:"attendance-checkin-section",children:[pt&&e.jsxs("div",{className:"gps-info-box",children:[e.jsx("div",{className:"gps-icon",children:e.jsx(ce,{name:"pin",size:28})}),e.jsxs("div",{className:"gps-text",children:[e.jsx("p",{className:"gps-title",children:"GPS 위치 확인 필요"}),e.jsxs("p",{className:"gps-description",children:[pt.placeName||"출석 장소"," 반경 ",Ca,"m 이내에서 출석 가능"]}),e.jsx("p",{className:"gps-address",children:pt.address})]})]}),pt&&!it&&e.jsx("button",{className:"attendance-location-btn",onClick:Qa,disabled:bn,children:bn?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"spinner",children:"⟳"}),"위치 확인 중..."]}):e.jsxs(e.Fragment,{children:[e.jsx(ce,{name:"pin",size:14})," 현재 위치 확인"]})}),it&&e.jsxs("div",{className:"location-confirmed",children:[e.jsx("span",{className:"confirm-icon",children:e.jsx(ce,{name:"check",size:14})}),e.jsxs("span",{children:["위치 확인됨 (정확도: ",it.accuracy.toFixed(0),"m)"]})]}),yn&&e.jsx("div",{className:"attendance-error",children:yn}),e.jsx("button",{className:"attendance-submit-btn",onClick:Xa,disabled:vn||pt&&!it||!Se?.can_checkin,children:vn?"출석 처리 중...":"출석하기"}),Se?.message&&e.jsx("div",{className:"attendance-message",children:Se.message})]})]})]})}),o==="live"&&i&&(()=>{const s=i?.block_data?.content||{},a=s.live||{},c=a.platform||"jitsi",f=c==="jitsi",j=f?"iframe":a.open_mode||"both",P=a.room_id||"",D=ee?.domain||"meet.gesture.day",S=a.url||(f&&P?`https://${D}/${P}`:""),le=xs(s),Ne=le.active?le.state:"none",ke=he||Ne==="none"||Ne==="open",Je=he||!ee||ee.host_active!==!1,Me=ke&&Je,V=!!ee?.attended,je=!!ee?.tracks_progress||f&&Number(s.learning_time)>0&&Number(s.attendence_percent)>0,_e=Ve?.pct??ee?.progress_percent??0,Ae=Ve?.achieved??V,ps=Number(s.attendence_percent)||0,Qs=c==="zoom"?"Zoom":c==="meet"?"Google Meet":"자체 화상수업 (Grend Live)",E=f&&ue&&!!P,ie=!f&&ue&&(j==="iframe"||j==="both")&&!!S,be=s.title||i?.title||"실시간수업";return e.jsx("div",{className:"material-content-section",children:e.jsxs("div",{className:"material-container live-block",children:[e.jsxs("div",{className:"attendance-header",children:[e.jsxs("h3",{className:"attendance-title",style:{display:"flex",alignItems:"center",gap:"8px"},children:[e.jsx("img",{src:us("live"),alt:"실시간수업",style:{width:"22px",height:"22px"}}),be]}),e.jsxs("div",{className:"attendance-badges",style:{display:"flex",gap:"8px",alignItems:"center",flexWrap:"wrap",marginTop:"8px"},children:[e.jsx("span",{className:"attendance-badge managed",children:Qs}),le.active&&e.jsxs("span",{className:"attendance-badge",style:{background:"#eef2ff",color:"#4338ca"},children:[Et(le)," · ",sa(le)]}),Ae?e.jsxs("span",{className:"attendance-badge",style:{background:"#dcfce7",color:"#15803d"},children:[e.jsx(ce,{name:"check",size:14})," 출석 인정"]}):je&&!he&&ue?e.jsxs("span",{className:"attendance-badge",style:{background:"#eef2ff",color:"#4338ca"},children:["시청 ",_e,"% / 인정 ",ps,"%"]}):V?e.jsxs("span",{className:"attendance-badge",style:{background:"#dcfce7",color:"#15803d"},children:[e.jsx(ce,{name:"check",size:14})," 출석함"]}):null]})]}),e.jsxs("div",{className:"attendance-body",style:{padding:"16px 0"}
12,children:[s.description&&e.jsx("div",{style:{marginBottom:"16px",color:"#4b5563",lineHeight:1.6},dangerouslySetInnerHTML:{__html:s.description}}),E&&e.jsxs("div",{style:{marginBottom:"16px"},children:[e.jsx(Gi,{domain:D,roomId:P,displayName:ee?.display_name,isHost:he||!!ee?.is_host,jwt:ee?.jwt,trackProgress:!he,blockId:n,cwUuid:l,cohortId:h,onProgress:(Fe,Xs)=>Ge({pct:Fe,achieved:Xs}),onClose:()=>{$e(!1),I.getLiveStatus(n,l,h).then(Fe=>de(Fe)).catch(()=>{})},recTitle:be,endHandleRef:Oe,onClientRecorded:()=>me(Fe=>Fe+1),onRecordingChange:Fe=>{Fe||window.setTimeout(()=>me(Xs=>Xs+1),8e3)}}),je&&!he&&e.jsxs("div",{style:{marginTop:"10px"},children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",fontSize:"13px",color:"#4b5563",marginBottom:"4px"},children:[e.jsx("span",{children:"시청 진도"}),e.jsxs("span",{style:{fontWeight:700,color:Ae?"#15803d":"#4338ca"},children:[_e,"% ",Ae?"· 출석 인정":`(인정 기준 ${ps}%)`]})]}),e.jsx("div",{style:{height:"8px",background:"#e5e7eb",borderRadius:"999px",overflow:"hidden"},children:e.jsx("div",{style:{width:`${Math.min(100,_e)}%`,height:"100%",background:Ae?"#22c55e":"#4f46e5",transition:"width .4s"}})}),e.jsx("p",{style:{fontSize:"12px",color:"#9ca3af",marginTop:"6px"},children:"화면을 보고 있는 동안 시청 시간이 인정됩니다. 창을 최소화하거나 회의에서 나가면 인정이 멈춥니다."})]})]}),ie&&e.jsxs("div",{style:{marginBottom:"16px"},children:[e.jsx("iframe",{src:S,title:be,allow:"camera; microphone; fullscreen; display-capture; autoplay; clipboard-write",style:{width:"100%",height:"68vh",border:0,borderRadius:"10px",background:"#000"}}),e.jsxs("p",{style:{fontSize:"12px",color:"#b45309",marginTop:"8px"},children:["Zoom·Google Meet은 화면 안 임베드가 차단될 수 있습니다. 화면이 비어 있으면 아래 ",e.jsx("b",{children:"새 창으로 열기"}),"를 눌러주세요."]})]}),!Me&&Ne==="before"&&e.jsxs("div",{className:"attendance-message",style:{marginBottom:"12px"},children:["아직 입장 시간이 아닙니다. (",Et(le),")"]}),!Me&&Ne==="closed"&&e.jsx("div",{className:"attendance-message",style:{marginBottom:"12px"},children:"실시간수업 시간이 종료되었습니다."}),!Je&&ke&&e.jsxs("div",{className:"attendance-message",style:{marginBottom:"12px"},children:[e.jsx("b",{children:"아직 수업이 시작되지 않았습니다."})," 교수자가 회의를 열면 입장할 수 있습니다.",e.jsx("span",{style:{color:"#9ca3af"},children:" (자동으로 확인합니다)"})]}),e.jsxs("div",{style:{display:"flex",gap:"10px",flexWrap:"wrap"},children:[!E&&Me&&(f||!he)&&e.jsx("button",{className:"attendance-submit-btn",onClick:Ha,disabled:Te||!S,style:{minWidth:"160px"},children:Te?he?"여는 중...":"입장 중...":he?"회의 시작 (호스트)":V||ue?"다시 입장":"입장"}),S&&!f&&Me&&(j==="newwindow"||j==="both"||ie)&&e.jsxs("button",{className:"attendance-location-btn",onClick:()=>window.open(S,"_blank","noopener,noreferrer"),disabled:!Me,children:[e.jsx(ce,{name:"link",size:14})," 새 창으로 열기"]})]}),he&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"attendance-managed-message",style:{margin:"20px 0 16px"},children:[e.jsx("div",{className:"managed-icon",children:e.jsx(ce,{name:"clipboard",size:28})}),e.jsxs("p",{children:[e.jsx("b",{children:"회의 시작"}),"을 누르면 강의실 안에서 ",e.jsx("b",{children:"호스트"}),"로 입장합니다. 학습자는 일반 참여자로 들어오며, ",e.jsx("b",{children:"입장"})," 시점에 출석이 기록됩니다. 아래에서 직접 보정할 수 있습니다."]})]}),e.jsx(zi,{blockId:n,cwUuid:l,cohortId:h})]}),e.jsxs("div",{style:{marginTop:"20px",paddingTop:"16px",borderTop:"1px solid #e5e7eb"},children:[e.jsx("h4",{style:{fontWeight:700,margin:"0 0 10px",fontSize:"15px"},children:"녹화 다시보기"}),e.jsx(Ji,{blockId:n,cwUuid:l,cohortId:h,canManage:he,refreshKey:Pe})]}),!he&&Ae&&e.jsx("div",{className:"attendance-message",style:{marginTop:"12px",color:"#15803d"},children:"출석이 인정되었습니다."}),!he&&!Ae&&V&&e.jsx("div",{className:"attendance-message",style:{marginTop:"12px",color:"#15803d"},children:"입장(출석)이 기록되었습니다."})]})]})})})(),za&&i&&e.jsx("div",{className:"material-content-section",children:e.jsxs("div",{className:"material-container notice-block",children:[e.jsxs("div",{className:"attendance-header",children:[e.jsxs("h3",{className:"attendance-title",style:{display:"flex",alignItems:"center",gap:"8px"},children:[e.jsx("img",{src:us("notice"),alt:"공지",style:{width:"22px",height:"22px"}}),i?.block_data?.content?.title||i?.title||"공지사항"]}),he&&e.jsx("button",{className:"notice-readers-btn",title:"누가 읽었는지 보기",onClick:()=>Bt({loading:!0}),children:qs?`${qs.read}/${qs.total} 읽음`:"읽음 현황"})]}),e.jsx("div",{className:"notice-block-body",dangerouslySetInnerHTML:{__html:i?.block_data?.content?.description||"<p>내용이 없습니다.</p>"}})]})}),Mn&&i&&(()=>{const s=Da(i),a=Tt(o);return e.jsx("div",{className:"material-content-section",children:e.jsxs("div",{className:"material-container",children:[e.jsx("div",{className:"attendance-header",children:e.jsxs("h3",{className:"attendance-title",style:{display:"flex",alignItems:"center",gap:"8px"},children:[e.jsx("img",{src:us(o),alt:a,style:{width:"22px",height:"22px"}}),i?.block_data?.content?.title||i?.title||a]})}),i?.block_data?.content?.description&&e.jsx("div",{className:"material-description",style:{color:"#555",fontSize:"0.9rem",padding:"12px 16px 0",lineHeight:1.6},dangerouslySetInnerHTML:{__html:i.block_data.content.description}}),s.length>0?e.jsx("div",{className:"material-body",children:e.jsx(Kn,{attachments:s,blockId:n||"",videoId:""})}):e.jsx("div",{style:{padding:"30px",textAlign:"center",color:"#9ca3af"},children:"등록된 파일이 없습니다."})]})})})(),e.jsxs("div",{className:"video-navigation",children:[e.jsxs("button",{className:"nav-btn prev-btn",onClick:()=>ye.prev&&St(ye.prev.id,ye.prev.type),disabled:!ye.prev,children:[e.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",children:e.jsx("polyline",{points:"15 18 9 12 15 6",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})}),e.jsx("span",{children:r("videoPlayer.prev","이전")})]}),e.jsxs("button",{className:"nav-btn next-btn",onClick:()=>ye.next&&St(ye.next.id,ye.next.type),disabled:!ye.next,children:[e.jsx("span",{children:r("videoPlayer.next","다음")}),e.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",children:e.jsx("polyline",{points:"9 18 15 12 9 6",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})]})]})]}),o==="video"&&e.jsxs("div",{className:"ai-tutor-section",children:[e.jsxs("div",{className:"video-playlist",children:[e.jsxs("div",{className:"video-playlist-header",children:[e.jsx("span",{children:r("videoPlayer.videoList","동영상 목록")}),e.jsxs("label",{className:"video-autonext",title:"영상이 끝나면 아직 안 본 다음 영상으로 이어서 봅니다",children:[e.jsx("input",{type:"checkbox",checked:W,onChange:s=>$a(s.target.checked)}),e.jsx("span",{children:r("videoPlayer.autoNext","이어서 보기")})]})]}),e.jsx("div",{className:"video-playlist-content",ref:oe,children:Y.flatMap(s=>s.sessions?.flatMap(a=>a.blocks?.filter(c=>c.blockType?.toLowerCase()==="video").map(c=>{const f=c.thumbnail_url||Ys(c.blockData?.content?.video)||Ys(c.video)||Ys(c.content?.video)||null;return e.jsxs("div",{className:`video-playlist-item ${c.blockId===n?"active":""}`,onClick:()=>St(c.blockId,c.blockType),children:[e.jsx("div",{className:"video-playlist-thumbnail",children:f?e.jsx("img",{src:f,alt:a.sessionTitle}):e.jsx("div",{className:"default-thumbnail",children:e.jsx("img",{src:"/lmsicons/todo/목록/동영상.svg",alt:"동영상",style:{width:24,height:24,filter:"brightness(0) invert(1)"}})})}),e.jsxs("div",{className:"video-playlist-info",children:[e.jsxs("div",{className:"video-playlist-session",children:[s.moduleNumber,r("videoPlayer.week","주차")," ",a.sessionNumber,r("videoPlayer.session","차시")]}),e.jsx("div",{className:"video-playlist-title",children:Ht(c.title||a.sessionTitle)}),(()=>{const j=Ln(c.blockId);if(j===null)return null;const P=Is(c.blockId);return e.jsxs("div",{className:"video-playlist-progress",children:[e.jsx("div",{className:"vpp-bar",children:e.jsx("div",{className:`vpp-fill ${P?"done":""}`,style:{width:`${j}%`}})}),e.jsx("span",{className:`vpp-text ${P?"done":""}`,children:P?"완료":`${j}%`})]})})()]})]},c.blockId)}))||[])})]}),wt.length>0&&e.jsx(Ei,{sessionTitle:k?.sessionTitle||"",moduleTitle:k?.moduleTitle||"",blockTitle:On,courseTitle:N?.title||"",videoId:He?.video_id||"",courseId:l,blockId:n})]})]})]})]}),G&&e.jsx("div",{className:"next-video-ask",onClick:()=>u(null),children:e.jsxs("div",{className:"next-video-ask-box",onClick:s=>s.stopPropagation(),children:[e.jsx("h4",{children:r("videoPlayer.nextAskTitle","다음 동영상을 이어서 보시겠습니까?")}),e.jsx("p",{className:"next-video-ask-label",children:G.label}),e.jsx("p",{className:"next-video-ask-title",children:G.title}),e.jsxs("div",{className:"next-video-ask-actions",children:[e.jsx("button",{className:"ghost",onClick:()=>u(null),children:r("common.no","아니오")}),e.jsx("button",{className:"primary",onClick:()=>{const s=G;u(null),St(s.blockId,"video")},children:r("common.yes","예")})]})]})}),De&&e.jsx("div",{className:"notice-readers-overlay",onClick:s=>{s.target===s.currentTarget&&Bt(null)},children:e.jsxs("div",{className:"notice-readers-box",children:[e.jsxs("div",{className:"notice-readers-head",children:[e.jsx("h3",{children:"공지 열람 현황"}),e.jsx("button",{onClick:()=>Bt(null),"aria-label":"닫기",children:e.jsx(ce,{name:"close",size:18})})]}),De.loading?e.jsx("p",{className:"notice-readers-msg",children:"불러오는 중..."}):De.error?e.jsx("p",{className:"notice-readers-msg",children:De.error}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"notice-readers-sum",children:[e.jsxs("span",{children:["수강생 ",e.jsx("b",{children:De.total_students})]}),e.jsxs("span",{className:"ok",children:["읽음 ",e.jsx("b",{children:De.read_count})]}),e.jsxs("span",{className:"no",children:["안 읽음 ",e.jsx("b",{children:De.unread_count})]})]}),e.jsxs("div",{className:"notice-readers-tabs",children:[e.jsxs("button",{className:Ct==="unread"?"active":"",onClick:()=>Pn("unread"),children:["안 읽음 (",De.unread_count,")"]}),e.jsxs("button",{className:Ct==="read"?"active":"",onClick:()=>Pn("read"),children:["읽음 (",De.read_count,")"]})]}),e.jsxs("ul",{className:"notice-readers-list",children:[(Ct==="read"?De.read:De.unread).map(s=>e.jsxs("li",{children:[e.jsxs("span",{className:"who",children:[s.user_name," ",e.jsx("i",{children:s.user_id})]}),Ct==="read"&&e.jsx("span",{className:"when",children:Lt(s.first_viewed)?.toLocaleStr
12ing("ko-KR",{timeZone:"Asia/Seoul"})??""})]},s.user_id)),(Ct==="read"?De.read:De.unread).length===0&&e.jsx("li",{className:"empty",children:Ct==="read"?"아직 읽은 사람이 없습니다.":"모두 읽었습니다."})]})]})]})})]})},sr=n=>n==="single_choice"||n==="single_multiple_choice"?"객관식 단답형":n==="multi_choice"||n==="multiple_choice"||n==="multi_multiple_choice"?"객관식 복수형":n==="short_answer"||n==="subjective"||n==="subjective_question"?"단답형":n==="long_answer"||n==="essay"||n==="descriptive"?"서술형":n==="ox_quiz"||n==="ox"?"O / X":n,nr=({blockId:n,cwUuid:l,cohortId:h,blockType:d,blockTitle:v,onClose:r})=>{const[i,y]=t.useState(!1),[T,$]=t.useState(!1),[F,A]=t.useState([]),[N,b]=t.useState([]),[k,w]=t.useState(null),[p,K]=t.useState(""),[Z,Q]=t.useState(""),[g,B]=t.useState({}),[W,O]=t.useState({}),G=t.useCallback(async()=>{y(!0);try{const o={cw_uuid:l};h&&(o.cohort_id=h);const R=(await Ce.get(`/lms/grade-by-block/instructor/block/${n}/submissions`,{params:o})).data||{};A(R.questions||[]),b(R.students||[])}catch(o){console.error("[SubmissionGradeModal] load failed",o),A([]),b([])}finally{y(!1)}},[n,l,h]);t.useEffect(()=>{G()},[G]);const u=N.find(o=>o.grade_user_id===k)||null,q=o=>{if(w(o.grade_user_id),d==="assignment")K(o.is_graded&&o.score_earned!=null?String(o.score_earned):""),Q(o.feedback_text||"");else{const z={},R={};(o.questions||[]).forEach(m=>{m.manual_points!=null&&(z[m.index]=String(m.manual_points)),m.feedback_text&&(R[m.index]=m.feedback_text)}),B(z),O(R)}},H=async()=>{if(!u)return;const o=u.max_score||0,z=Number(p);if(p===""||isNaN(z)){alert("점수를 입력하세요.");return}if(z<0||o&&z>o){alert(`점수는 0 ~ ${o} 사이여야 합니다.`);return}$(!0);try{await Ce.post("/lms/grade-by-block/instructor/assignment/grade",{block_id:n,cw_uuid:l,cohort_id:h,grade_user_id:u.grade_user_id,score_earned:z,feedback_text:Z}),await G()}catch(R){alert(`저장 실패: ${R?.response?.data?.detail||R?.message||""}`)}finally{$(!1)}},Y=async()=>{if(!u)return;const o=(u.questions||[]).filter(m=>m.needs_manual),z={},R={};for(const m of o){const J=g[m.index];if(J===void 0||J==="")continue;const ve=Number(J);if(isNaN(ve)||ve<0||m.max_score&&ve>m.max_score){alert(`${m.index+1}번 점수는 0 ~ ${m.max_score} 사이여야 합니다.`);return}z[String(m.index)]=ve,W[m.index]&&(R[String(m.index)]=W[m.index])}if(Object.keys(z).length===0){alert("채점할 점수를 입력하세요.");return}$(!0);try{await Ce.post("/lms/grade-by-block/instructor/exam/grade",{block_id:n,cw_uuid:l,cohort_id:h,grade_user_id:u.grade_user_id,question_scores:z,question_feedback:R}),await G()}catch(m){alert(`저장 실패: ${m?.response?.data?.detail||m?.message||""}`)}finally{$(!1)}},pe=N.filter(o=>o.submitted&&o.is_graded).length,ye=N.filter(o=>o.submitted).length,C=o=>o.submitted?o.is_graded?e.jsx("span",{className:"sgm-badge done",children:"채점완료"}):e.jsx("span",{className:"sgm-badge pending",children:"채점대기"}):e.jsx("span",{className:"sgm-badge none",children:"미제출"});return tn.createPortal(e.jsx("div",{className:"sgm-overlay",onClick:o=>{o.target===o.currentTarget&&r()},children:e.jsxs("div",{className:"sgm-dialog",children:[e.jsxs("div",{className:"sgm-header",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"sgm-title",children:v||(d==="exam"?"시험 채점":"과제 채점")}),e.jsxs("div",{className:"sgm-subtitle",children:["제출 ",e.jsx("strong",{children:ye}),"명 · 채점완료 ",e.jsx("strong",{children:pe}),"명"]})]}),e.jsx("button",{className:"sgm-close",onClick:r,children:"✕"})]}),e.jsxs("div",{className:"sgm-body",children:[e.jsx("div",{className:"sgm-list",children:i?e.jsx("div",{className:"sgm-empty",children:"불러오는 중..."}):N.length===0?e.jsx("div",{className:"sgm-empty",children:"수강생이 없습니다."}):N.map(o=>e.jsxs("button",{className:`sgm-list-item ${k===o.grade_user_id?"active":""} ${o.submitted?"":"dim"}`,onClick:()=>q(o),children:[e.jsxs("span",{className:"sgm-list-name",children:[o.grade_user_name,e.jsx("small",{children:o.grade_user_id})]}),C(o)]}
12,o.grade_user_id))}),e.jsx("div",{className:"sgm-detail",children:u?u.submitted?d==="assignment"?e.jsxs("div",{className:"sgm-assign",children:[e.jsxs("div",{className:"sgm-detail-head",children:[e.jsx("strong",{children:u.grade_user_name})," (",u.grade_user_id,")",u.submitted_at&&e.jsxs("span",{className:"sgm-when",children:["제출: ",Lt(u.submitted_at)?.toLocaleString("ko-KR",{timeZone:"Asia/Seoul"})]})]}),u.text_content?e.jsxs("div",{className:"sgm-section",children:[e.jsx("div",{className:"sgm-section-title",children:"제출 내용"}),e.jsx("div",{className:"sgm-text-content",children:u.text_content})]}):null,u.files&&u.files.length>0&&e.jsxs("div",{className:"sgm-section",children:[e.jsx("div",{className:"sgm-section-title",children:"제출 파일"}),e.jsx("ul",{className:"sgm-files",children:u.files.map((o,z)=>e.jsx("li",{children:o.file_url?e.jsx("a",{href:o.file_url,target:"_blank",rel:"noreferrer",children:o.original_name||`파일 ${z+1}`}):o.original_name||`파일 ${z+1}`},z))})]}),!u.text_content&&(!u.files||u.files.length===0)&&e.jsx("div",{className:"sgm-section sgm-muted",children:"제출 내용이 없습니다."}),e.jsxs("div",{className:"sgm-grade-form",children:[e.jsxs("label",{className:"sgm-field",children:[e.jsxs("span",{children:["점수 ",e.jsxs("small",{children:["(만점 ",u.max_score??0,")"]})]}),e.jsx("input",{type:"number",min:0,max:u.max_score??void 0,value:p,onChange:o=>K(o.target.value),placeholder:"점수 입력"})]}),e.jsxs("label",{className:"sgm-field",children:[e.jsx("span",{children:"피드백"}),e.jsx("textarea",{rows:4,value:Z,onChange:o=>Q(o.target.value),placeholder:"학생에게 보일 피드백 (선택)"})]}),e.jsx("button",{className:"sgm-save",onClick:H,disabled:T,children:T?"저장 중...":u.is_graded?"채점 수정":"채점 저장"})]})]}):e.jsxs("div",{className:"sgm-exam",children:[e.jsxs("div",{className:"sgm-detail-head",children:[e.jsx("strong",{children:u.grade_user_name})," (",u.grade_user_id,")",e.jsxs("span",{className:"sgm-when",children:[u.total_earned??0," / ",u.total_max??0,"점",typeof u.pending_manual=="number"&&u.pending_manual>0&&e.jsxs("em",{className:"sgm-pending",children:[" · 채점대기 ",u.pending_manual,"문항"]})]})]}),(u.questions||[]).map(o=>{const z=F.find(R=>R.index===o.index);return e.jsxs("div",{className:`sgm-q ${o.needs_manual?"manual":"auto"}`,children:[e.jsxs("div",{className:"sgm-q-head",children:[e.jsxs("span",{className:"sgm-q-no",children:[o.index+1,"."]}),e.jsx("span",{className:"sgm-q-type",children:sr(o.type)}),e.jsx("span",{className:"sgm-q-title",children:z?.title}),e.jsxs("span",{className:"sgm-q-max",children:["배점 ",o.max_score]})]}),e.jsx("div",{className:"sgm-q-answer",children:o.type==="long_answer"||o.type==="short_answer"||o.type==="subjective"||o.type==="subjective_question"?e.jsx("div",{className:"sgm-answer-text",children:o.answer_text||e.jsx("em",{className:"sgm-muted",children:"무응답"})}):e.jsx("div",{className:"sgm-answer-choices",children:(z?.options||[]).map((R,m)=>{const J=(o.selected_indexes||[]).includes(m);return e.jsxs("span",{className:`sgm-choice ${J?"picked":""} ${R.is_correct?"correct":""}`,children:[J?"●":"○"," ",R.text,R.is_correct?" ✓":""]},m)})})}),o.needs_manual?e.jsxs("div",{className:"sgm-q-grade",children:[e.jsxs("label",{children:["점수",e.jsx("input",{type:"number",min:0,max:o.max_score,value:g[o.index]??"",onChange:R=>B(m=>({...m,[o.index]:R.target.value})),placeholder:`0~${o.max_score}`})]}),e.jsx("input",{className:"sgm-q-fb",type:"text",value:W[o.index]??"",onChange:R=>O(m=>({...m,[o.index]:R.target.value})),placeholder:"피드백 (선택)"})]}):e.jsxs("div",{className:"sgm-q-auto",children:["자동채점: ",o.auto_is_correct?"정답":"오답"," · ",o.score_earned,"/",o.max_score,"점"]})]},o.index)}),e.jsx("button",{className:"sgm-save",onClick:Y,disabled:T,children:T?"저장 중...":"채점 저장"})]}):e.jsx("div",{className:"sgm-empty sgm-detail-empty",children:"아직 제출하지 않은 학생입니다."}):e.jsx("div",{className:"sgm-empty sgm-detail-empty",children:"왼쪽에서 학생을 선택하세요."})})]})]})}),document.body)},na=n=>{const l=Lt(n);
12return l?l.toLocaleString("ko-KR",{timeZone:"Asia/Seoul",dateStyle:"short",timeStyle:"short"}):""},ar=({cwUuid:n,kind:l,ident:h,title:d,onClose:v})=>{const[r,i]=t.useState(null),[y,T]=t.useState("unread"),[$,F]=t.useState("");t.useEffect(()=>{let N=!1;return Ce.get(`/lms/cws-notices/${n}/readers/${l}/${h}`).then(b=>{N||i(b.data)}).catch(b=>{N||F(b?.response?.data?.detail||"열람 현황을 불러오지 못했습니다.")}),()=>{N=!0}},[n,l,h]),t.useEffect(()=>{const N=b=>{b.key==="Escape"&&v()};return window.addEventListener("keydown",N),()=>window.removeEventListener("keydown",N)},[v]);const A=r?y==="read"?r.read:r.unread:[];return e.jsx("div",{className:"nrm-veil",onClick:v,children:e.jsxs("div",{className:"nrm-box",onClick:N=>N.stopPropagation(),role:"dialog","aria-label":"공지 열람 현황",children:[e.jsxs("header",{className:"nrm-head",children:[e.jsxs("div",{children:[e.jsx("h3",{children:"공지 열람 현황"}),d&&e.jsx("p",{title:d,children:d})]}),e.jsx("button",{onClick:v,"aria-label":"닫기",children:"✕"})]}),$?e.jsx("p",{className:"nrm-msg nrm-err",children:$}):r?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"nrm-sum",children:[e.jsxs("span",{children:["수강생 ",e.jsx("b",{children:r.total_students})]}),e.jsxs("span",{children:["읽음 ",e.jsx("b",{className:"ok",children:r.read_count})]}),e.jsxs("span",{children:["안 읽음 ",e.jsx("b",{className:"no",children:r.unread_count})]})]}),e.jsxs("div",{className:"nrm-tabs",role:"tablist",children:[e.jsxs("button",{role:"tab","aria-selected":y==="unread",className:y==="unread"?"on":"",onClick:()=>T("unread"),children:["안 읽음 (",r.unread_count,")"]}),e.jsxs("button",{role:"tab","aria-selected":y==="read",className:y==="read"?"on":"",onClick:()=>T("read"),children:["읽음 (",r.read_count,")"]})]}),e.jsx("div",{className:"nrm-list",children:A.length===0?e.jsx("p",{className:"nrm-msg",children:r.total_students===0?"이 강좌에 수강생이 없습니다.":y==="unread"?"모두 읽었습니다.":"아직 읽은 수강생이 없습니다."}):A.map(N=>e.jsxs("div",{className:"nrm-row",children:[e.jsx("span",{className:"nrm-name",children:N.user_name||"(이름 없음)"}),e.jsx("span",{className:"nrm-id",children:N.user_id}),y==="read"&&e.jsxs("span",{className:"nrm-when",title:`마지막 ${na(N.last_viewed)}`,children:[na(N.first_viewed),(N.count||1)>1&&` · ${N.count}회`]})]},N.user_id))})]}):e.jsx("p",{className:"nrm-msg",children:"불러오는 중..."})]})})},st=n=>n?n.replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/\s+/g," ").trim():"",ir=({cwUuid:n,cohortId:l,onContinueLearning:h})=>{const{t:d}=gs("lms"),[v,r]=t.useState([]),[i,y]=t.useState(!0),[T,$]=t.useState(null),[F,A]=t.useState({}),[N,b]=t.useState({}),[k,w]=t.useState({}),[p,K]=t.useState({}),[Z,Q]=t.useState(null),[g,B]=t.useState(null),[W,O]=t.useState(!1),[G,u]=t.useState({}),[q,H]=t.useState(null),[Y,pe]=t.useState([]),[ye,C]=t.useState(!1),[o,z]=t.useState(!1),{canManage:R}=fi(n),[m,J]=t.useState({}),[ve,xe]=t.useState(null),[Ie,oe]=t.useState(null),[ee,de]=t.useState({}),[Te,Ze]=t.useState(null);t.useEffect(()=>{const _=async()=>{try{y(!0),$(null);const L=await I.getCWSItem(n);L.course_structure&&Array.isArray(L.course_structure)&&L.course_structure.length>0?(r(L.course_structure),await Ve(L.course_structure),await Ge(L.course_structure)):r([])}catch(L){console.error("Failed to load course structure:",L),$(d("syllabus.loadError","Failed to load syllabus."))}finally{y(!1)}};return _(),window.addEventListener("syllabusUpdated",_),()=>window.removeEventListener("syllabusUpdated",_)},[n,l]),t.useEffect(()=>{(async()=>{try{const L=await Ce.get("/lms/instructors/my-courses"),X=L.data?.courses||(Array.isArray(L.data)?L.data:[]);z(X.some(M=>M.cw_uuid===n))}catch{z(!1)}})()},[n]),t.useEffect(()=>{if(J({}),!R||!n)return;const _=new AbortController;return(async()=>{try{const L={video_only:!0,include_students:!1};l&&(L.cohort_id=l);const X=await Ce.get(`/lms/grade-by-block/instructor/cws/${n}/matrix`,{params:L,signal:_.signal}),M=X.data?.blocks||[],ae={},x=X.data?.total_students||0;M.forEach(ge=>{ae[ge.block_id]={completed:ge.completed_count||0,total:x}}),M.length,J(ae)}catch(L){if(L?.name==="CanceledError"||L?.code==="ERR_CANCELED")return;console.warn("[SyllabusViewer] matrix fetch failed",L)}})(),()=>_.abort()},[R,n,l]),t.useEffect(()=>{if(de({}),!R||!n)return;const _=new AbortController;return(async()=>{try{const L=await Ce.get(`/lms/cws-notices/${n}/all`,{signal:_.signal}),X={};
12(L.data?.items||[]).forEach(M=>{M.kind==="block"&&(X[M.id]={read:M.read_count||0,total:M.total_students||0})}),de(X)}catch(L){if(L?.name==="CanceledError"||L?.code==="ERR_CANCELED")return;console.warn("[SyllabusViewer] 공지 열람 수 조회 실패",L)}})(),()=>_.abort()},[R,n]),t.useEffect(()=>{const _=async()=>{const L=[];if(v.forEach(M=>M.sessions?.forEach(ae=>ae.blocks?.forEach(x=>{x.blockType==="material"&&L.push(x.blockId)}))),L.length===0)return;const X={};await Promise.all(L.map(async M=>{try{const x=(await Ce.get(`/lms/material/${M}/access-logs`)).data?.items||[];X[M]={views:x.filter(ge=>ge.viewed).length,downloads:x.filter(ge=>ge.downloaded).length}}catch{X[M]={views:0,downloads:0}}})),u(X)};v.length>0&&_()},[v]);const ue=async(_,L)=>{H({blockId:_,title:L}),C(!0);try{const M=(await Ce.get(`/lms/material/${_}/access-logs`)).data?.items||[];let ae=[];try{const te=await Ce.get(`/lms/registrations/${n}/students?page=1&size=500`);ae=te.data?.items||te.data||[]}catch{}const x=new Map(M.map(te=>[te.user_id,te])),ge=ae.map(te=>{const Ee=x.get(te.stu_id);return{user_id:te.stu_id,user_name:te.stu_name,viewed:Ee?.viewed||!1,downloaded:Ee?.downloaded||!1,logs:Ee?.logs||[]}});M.forEach(te=>{ge.find(Ee=>Ee.user_id===te.user_id)||ge.push(te)}),pe(ge)}catch{pe([])}finally{C(!1)}};t.useEffect(()=>{if(!v.length)return;const _=new URLSearchParams(window.location.search).get("block");if(!_||!v.some(M=>M.sessions?.some(ae=>ae.blocks?.some(x=>x.blockId===_))))return;Q(_),O(!0);const X=new URL(window.location.href);X.searchParams.delete("block"),window.history.replaceState({},"",X.toString())},[v]),t.useEffect(()=>{const _=L=>{const{blockId:X}=L.detail;Q(X),O(!0)};return window.addEventListener("openLastLearningBlock",_),()=>{window.removeEventListener("openLastLearningBlock",_)}},[]);const $e=_=>_.filter(L=>o||k[L.blockId]!==!1),Oe=_=>{const L=F[_.blockId];return L&&L!=="제목 없음"?L:me(_.blockType)},Ve=async _=>{const L=[];_.forEach(x=>{x.sessions.forEach(ge=>{ge.blocks.forEach(te=>{L.push({blockId:te.blockId,blockType:te.blockType})})})});const X={},M={},ae={};await Promise.all(L.map(async({blockId:x,blockType:ge})=>{try{if(ge==="attendance"){const te=await I.getAttendanceBlock(x);X[x]=te.title||"제목 없음",M[x]=!0}else{const te=await I.getBlock(x);X[x]=te.title||te.block_data?.content?.title||"제목 없음",M[x]=te.block_data?.content?.published!==!1;const Ee=xs(te.block_data?.content);Ee.active&&(ae[x]={range:Et(Ee),tip:en(Ee),state:Ee.state})}}catch(te){console.error(`Failed to load block ${x}:`,te),X[x]="제목 없음",M[x]=!1}})),A(X),w(M),b(ae)},Ge=async _=>{const L=new Set;_.forEach(M=>{M.sessions.forEach(ae=>{ae.blocks.forEach(x=>{x.blockType==="video"&&L.add(x.blockId)})})});const X={};await Promise.all(Array.from(L).map(async M=>{try{const ae=await I.getVideoProgress(M,l);X[M]={progress:Math.round(ae.progress_percent||0),achieve:ae.achieve||!1}}catch(ae){console.error(`Failed to load progress for block ${M}:`,ae),X[M]={progress:0,achieve:!1}}})),K(X)},Pe=_=>ra(_),me=_=>ia(_,d,"syllabus.blocks"),Re=_=>_?d("videoPlayer.complete","Complete"):d("videoPlayer.incomplete","Incomplete"),Ye=_=>({이론형:d("syllabus.methods.theory","Theory"),실습형:d("syllabus.methods.practice","Practice"),토론형:d("syllabus.methods.discussion","Discussion"),프로젝트형:d("syllabus.methods.project","Project"),theory:d("syllabus.methods.theory","Theory"),practice:d("syllabus.methods.practice","Practice"),discussion:d("syllabus.methods.discussion","Discussion"),project:d("syllabus.methods.project","Project")})[_]||_||"-",nt=(_,L)=>{const X=`last_learning_${n}`,M={blockId:_,blockType:L,timestamp:new Date().toISOString()};localStorage.setItem(X,JSON.stringify(M)),Q(_),B(L),O(!0)},Pt=()=>{O(!1),Q(null),B(null),v.length>0&&Ge(v)},Le=_=>{Q(_)};return i?e.jsx("div",{className:"syllabus-viewer",children:e.jsx("div",{className:"loading-message",children:d("syllabus.loading","Loading syllabus...")})}):T?e.jsx("div",{className:"syllabus-viewer",children:e.jsx("div",{className:"error-message",children:T})}):v.length===0?e.jsx("div",{className:"syllabus-viewer",children:e.jsx("div",{className:"empty-message",children:d("syllabus.empty","Syllabus has not been created yet.")})}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"syllabus-viewer",children:[e.jsx("div",{className:"syllabus-table-wrapper syllabus-desktop",children:e.jsxs("table",{className:"syllabus-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:"col-module",children:d("syllabus.table.week","Week")}),e.jsx("th",{className:"col-module-title",children:d("syllabus.table.weekName","Week Name")}),e.jsx("th",{className:"col-session",children:d("syllabus.table.session","Session")}),e.jsx("th",{className:"col-session-title",children:d("syllabus.table.sessionName","Session Name")}),e.jsx("th",{className:"col-instructor",children:d("syllabus.table.instructor","Instru
12ctor")}),e.jsx("th",{className:"col-duration",children:d("syllabus.table.duration","Duration (min)")}),e.jsx("th",{className:"col-method",children:d("syllabus.table.teachingMethod","Teaching Method")}),e.jsx("th",{className:"col-objectives",children:d("syllabus.table.learningObjectives","Learning Objectives")}),e.jsx("th",{className:"col-blocks",children:d("syllabus.table.learningBlocks","Learning Blocks")})]})}),e.jsx("tbody",{children:v.map((_,L)=>{const X=_.sessions.length||1;return e.jsx(fs.Fragment,{children:_.sessions.length===0?e.jsxs("tr",{children:[e.jsx("td",{className:"text-center",children:_.moduleNumber}),e.jsx("td",{children:st(_.moduleTitle)}),e.jsx("td",{colSpan:7,className:"empty-session",children:d("syllabus.noSessions","No sessions registered.")})]}):_.sessions.map((M,ae)=>e.jsxs("tr",{children:[ae===0&&e.jsxs(e.Fragment,{children:[e.jsx("td",{rowSpan:X,className:"text-center module-cell",children:_.moduleNumber}),e.jsx("td",{rowSpan:X,className:"module-title-cell",children:st(_.moduleTitle)})]}),e.jsx("td",{className:"text-center",children:M.sessionNumber}),e.jsx("td",{className:"session-title-cell",children:st(M.sessionTitle)}),e.jsx("td",{className:"text-center",children:M.instructor||"-"}),e.jsx("td",{className:"text-center",children:M.durationMinutes}),e.jsx("td",{className:"text-center",children:Ye(M.method)}),e.jsx("td",{className:"objectives-cell",children:M.learningObjectives.length>0?e.jsx("ul",{className:"objectives-list",children:M.learningObjectives.map((x,ge)=>e.jsx("li",{children:x},ge))}):e.jsx("span",{className:"text-gray-400",children:"-"})}),e.jsx("td",{className:"blocks-cell",children:$e(M.blocks).length>0?e.jsx("div",{className:"blocks-list",children:$e(M.blocks).map((x,ge)=>{const te=p[x.blockId],Ee=te?.progress||0,qe=Re(te?.achieve||!1);return e.jsxs("div",{className:"block-item block-item-clickable",onClick:()=>nt(x.blockId,x.blockType),style:{cursor:"pointer"},children:[e.jsx("img",{alt:me(x.blockType),className:"block-icon",src:Pe(x.blockType),style:{width:"20px",height:"20px"}}),e.jsxs("span",{className:"block-type",title:`${me(x.blockType)} · ${Oe(x)}`,children:[Oe(x),N[x.blockId]&&e.jsx("em",{className:`block-period block-period-${N[x.blockId].state}`,title:N[x.blockId].tip,children:N[x.blockId].range})]}),e.jsxs("span",{className:"block-stats",children:[x.blockType==="video"&&te&&e.jsxs("span",{className:"block-progress",style:{color:te.achieve?"#1E4199":"#666"},children:[Ee,"% ",qe]}),x.blockType==="video"&&R&&m[x.blockId]&&e.jsxs("span",{className:"block-completion-count block-chip",title:"학습자 학습 현황 보기",onClick:we=>{we.stopPropagation(),xe({blockId:x.blockId,title:F[x.blockId]||st(M.sessionTitle)||me(x.blockType)})},children:[m[x.blockId].completed,"/",m[x.blockId].total," 수료"]}),(x.blockType==="assignment"||x.blockType==="exam")&&R&&e.jsx("span",{className:"block-completion-count block-chip",title:"제출물 채점하기",onClick:we=>{we.stopPropagation(),oe({blockId:x.blockId,title:F[x.blockId]||st(M.sessionTitle)||me(x.blockType),type:x.blockType})},children:"채점"}),x.blockType==="notice"&&R&&e.jsx("span",{className:"block-read-count block-chip",title:"이 공지를 누가 읽었는지 보기",onClick:we=>{we.stopPropagation(),Ze({kind:"block",ident:x.blockId,title:F[x.blockId]||me(x.blockType)})},children:ee[x.blockId]?`${ee[x.blockId].read}/${ee[x.blockId].total} 읽음`:"읽음 현황"}),x.blockType==="material"&&G[x.blockId]&&e.jsxs("span",{className:"block-material-stat",style:{cursor:o?"pointer":"default"},onClick:we=>{o&&(we.stopPropagation(),ue(x.blockId,F[x.blockId]||me(x.blockType)))},title:o?"클릭하여 상세 이력 보기":"",children:[e.jsx(ce,{name:"eye",size:12})," ",G[x.blockId].views," · ",e.jsx(ce,{name:"arrow-down",size:12})," ",G[x.blockId].downloads]})]})]},ge)})}):e.jsx("span",{className:"text-gray-400",children:"-"})})]},`${L}-${ae}`))},L)})})]})}),e.jsx("div",{className:"syllabus-mobile",children:v.map((_,L)=>{const X=_.sessions[0]?.instructor||"-";return e.jsxs("div",{className:"syllabus-mobile-card",children:[e.jsxs("div",{className:"syllabus-mobile-header",children:[e.jsxs("div",{className:"syllabus-mobile-header-left",children:[e.jsx("span",{className:"syllabus-mobile-week-badge",children:_.moduleNumber}),e.jsx("span",{className:"syllabus-mobile-week-title",children:st(_.moduleTitle)})]}),e.jsx("span",{className:"syllabus-mobile-instructor",children:X})]}),e.jsx("div",{className:"syllabus-mobile-sessions",children:_.sessions.length===0?e.jsx("div",{className:"syllabus-mobile-empty",children:d("syllabus.noSessions","No sessions registered.")}):_.sessions.map((M,ae)=>e.jsxs("div",{className:"syllabus-mobile-session",children:[e.jsxs("div",{className:"syllabus-mobile-session-header",children:[e.jsx("span",{className:"syllabus-mobile-session-badge",children:M.sessionNumber}),e.jsx("span",{className:"syllabus-mobile-session-title",children:st(M.sessionTitle)})]}),$e(M.blocks).length>0&&e.jsx("div",{className:"syllabus-mobile-blocks",children:$e(M.blocks).map((x,ge)=>{const te=p[x.blockId],Ee=te?.progress||0,qe=te?.achieve||!1;return e.jsxs("button",{className:`syllabus-mobile-block-btn ${qe?"complete":""}`,onClick:()=>nt(x.blockId,x.blockType),children:[e.jsx("img",{alt:me(x.blockType),src:Pe(x.blockType),className:"syllabus-mobile-block-icon"}),e.jsxs("span",{className:"syllabus-mobile-block-type",title:me(x.blockType),children:[Oe
12(x),N[x.blockId]&&e.jsx("em",{className:`block-period block-period-${N[x.blockId].state}`,children:N[x.blockId].range})]}),x.blockType==="video"&&te&&e.jsxs("span",{className:`syllabus-mobile-block-progress ${qe?"complete":""}`,children:[Ee,"%"]}),x.blockType==="video"&&R&&m[x.blockId]&&e.jsxs("span",{style:{fontSize:"11px",color:"#1e40af",marginLeft:"6px",padding:"1px 6px",background:"#dbeafe",borderRadius:"8px",fontWeight:600},onClick:we=>{we.stopPropagation(),xe({blockId:x.blockId,title:F[x.blockId]||st(M.sessionTitle)||me(x.blockType)})},children:[m[x.blockId].completed,"/",m[x.blockId].total]}),(x.blockType==="assignment"||x.blockType==="exam")&&R&&e.jsx("span",{style:{fontSize:"11px",color:"#1e40af",marginLeft:"6px",padding:"1px 6px",background:"#dbeafe",borderRadius:"8px",fontWeight:600},onClick:we=>{we.stopPropagation(),oe({blockId:x.blockId,title:F[x.blockId]||st(M.sessionTitle)||me(x.blockType),type:x.blockType})},children:"채점"})]},ge)})})]},ae))})]},L)})})]}),W&&Z&&e.jsx(tr,{blockId:Z,cwUuid:n,cohortId:l,onClose:Pt,onNavigate:Le}),Te&&e.jsx(ar,{cwUuid:n,kind:Te.kind,ident:Te.ident,title:Te.title,onClose:()=>Ze(null)}),ve&&e.jsx(wi,{blockId:ve.blockId,cwUuid:n,cohortId:l,blockTitle:ve.title,onClose:()=>{if(xe(null),R){const _={video_only:!0};l&&(_.cohort_id=l),Ce.get(`/lms/grade-by-block/instructor/cws/${n}/matrix`,{params:_}).then(L=>{const X=L.data?.blocks||[],M={},ae=L.data?.total_students||0;X.forEach(x=>{M[x.block_id]={completed:x.completed_count||0,total:ae}}),J(M)}).catch(()=>{})}}}),Ie&&e.jsx(nr,{blockId:Ie.blockId,cwUuid:n,cohortId:l,blockType:Ie.type,blockTitle:Ie.title,onClose:()=>oe(null)}),q&&tn.createPortal(e.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.5)",zIndex:1e4,display:"flex",alignItems:"center",justifyContent:"center"},onClick:()=>H(null),children:e.jsxs("div",{style:{background:"#fff",borderRadius:"12px",width:"90vw",maxWidth:"800px",maxHeight:"80vh",display:"flex",flexDirection:"column",boxShadow:"0 20px 60px rgba(0,0,0,0.2)"},onClick:_=>_.stopPropagation(),children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",borderBottom:"1px solid #e5e7eb"},children:[e.jsxs("h3",{style:{margin:0,fontSize:"1.1rem",fontWeight:700},children:["학습자료 접근 이력 - ",q.title]}),e.jsx("button",{onClick:()=>H(null),"aria-label":"닫기",style:{background:"none",border:"none",cursor:"pointer",color:"#6b7280",lineHeight:0},children:e.jsx(ce,{name:"close",size:18})})]}),e.jsx("div",{style:{padding:"16px 20px",overflowY:"auto",flex:1},children:ye?e.jsx("div",{style:{textAlign:"center",padding:"30px",color:"#9ca3af"},children:"불러오는 중..."}):e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.85rem"},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{background:"#f9fafb"},children:[e.jsx("th",{style:{padding:"8px 10px",textAlign:"left",borderBottom:"1px solid #e5e7eb",fontWeight:600},children:"학습자"}),e.jsx("th",{style:{padding:"8px 10px",textAlign:"center",borderBottom:"1px solid #e5e7eb",fontWeight:600,width:"70px"},children:"열람"}),e.jsx("th",{style:{padding:"8px 10px",textAlign:"center",borderBottom:"1px solid #e5e7eb",fontWeight:600,width:"70px"},children:"다운로드"}),e.jsx("th",{style:{padding:"8px 10px",textAlign:"center",borderBottom:"1px solid #e5e7eb",fontWeight:600,width:"130px"},children:"최초 접근일"}),e.jsx("th",{style:{padding:"8px 10px",textAlign:"center",borderBottom:"1px solid #e5e7eb",fontWeight:600,width:"130px"},children:"최근 접근일"})]})}),e.jsx("tbody",{children:Y.length===0?e.jsx("tr",{children:e.jsx("td",{colSpan:5,style:{textAlign:"center",padding:"20px",color:"#9ca3af"},children:"데이터 없음"})}):Y.map((_,L)=>{const X=x=>Vt(x,"-","-"),M=_.logs?.[0]?.timestamp||"",ae=_.logs?.length>0?_.logs[_.logs.length-1].timestamp:"";return e.jsxs("tr",{style:{borderBottom:"1px solid #f3f4f6"},children:[e.jsxs("td",{style:{padding:"8px 10px"},children:[_.user_name," (",_.user_id,")"]}),e.jsx("td",{style:{padding:"8px 10px",textAlign:"center"},children:e.jsx("span",{style:{color:_.viewed?"#047857":"#dc2626",fontWeight:500},children:_.viewed?"O":"X"})}),e.jsx("td",{style:{padding:"8px 10px",textAlign:"center"},children:e.jsx("span",{style:{color:_.downloaded?"#047857":"#dc2626",fontWeight:500},children:_.downloaded?"O":"X"})}),e.jsx("td",{style:{padding:"8px 10px",textAlign:"center",fontSize:"0.8rem",color:"#6b7280"},children:X(M)}),e.jsx("td",{style:{padding:"8px 10px",textAlign:"center",fontSize:"0.8rem",color:"#6b7280"},children:X(ae)})]},L)})})]})})]})}),document.body)]})},rr=[{id:1,title:"호흡기계 구조와 기능",week:1,order:1,goals:["호흡기의 구조와 기능을 설명할 수 있다.","호흡조절기전과 방어기전을 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:2,title:"호흡기장애 대상자 자료수집",week:1,order:2,goals:["호흡생리를 설명할 수 있다.","호흡기장애 대상자의 주관적, 객관적 자료를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:3,title:"산과 염기",week:2,order:1,goals:["산-염기 균형의 기전을 설명할 수 있다.","산-염기 불균í
12˜•의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:4,title:"호흡기장애 대상자 간호",week:2,order:2,goals:["호흡장애 개선을 위한 간호를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:5,title:"상부호흡기장애 대상자 간호 1",week:3,order:1,goals:["감염성 질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:6,title:"상부호흡기장애 대상자 간호 2",week:3,order:2,goals:["신생물 질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다.","외상의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:7,title:"하부호흡기장애 대상자 간호 1",week:4,order:1,goals:["감염성 질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:8,title:"하부호흡기장애 대상자 간호 2",week:4,order:2,goals:["폐혈관질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박서진(동강대학교)"},{id:9,title:"하부호흡기장애 대상자 간호 3",week:5,order:1,goals:["흉막질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:10,title:"하부호흡기장애 대상자 간호 4",week:5,order:2,goals:["폐쇄폐질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:11,title:"하부호흡기장애 대상자 간호 5",week:6,order:1,goals:["폐암의 병태생리와 임상증상, 진단검사 방법을 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:12,title:"하부호흡기장애 대상자 간호 6",week:6,order:2,goals:["폐암의 치료 및 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:13,title:"하부호흡기장애 대상자 간호 7",week:7,order:1,goals:["외상의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:14,title:"하부호흡기장애 대상자 간호 8",week:7,order:2,goals:["기흉과 혈흉의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:15,title:"심장의 구조와 기능",week:8,order:1,goals:["심장의 기본적 구조와 기능을 설명할 수 있다.","심박출량 조절기전을 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:16,title:"심장장애 대상자 자료수집",week:8,order:2,goals:["심장장애 대상자의 주관적 자료를 통해 주요 간호문제를 설명할 수 있다.","심장장애 대상자의 객관적 자료를 통해 주요 간호문제를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:17,title:"심장장애 대상자 진단검사",week:9,order:1,goals:["심장질환의 진단검사의 목적, 방법, 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:18,title:"심장박동장애 1",week:9,order:2,goals:["동방결절에서 발생하는 부정맥의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:19,title:"심장박동장애 2",week:10,order:1,goals:["심방, 방실접합부, 심실에서 발생하는 부정맥의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:20,title:"심장박동장애 3",week:10,order:2,goals:["심장박동장애의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"박선화(청암대학교)"},{id:21,title:"울혈성 심부전",week:11,order:1,goals:["울혈성 심부전의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"이숙경(순천제일대학교)"},{id:22,title:"심장동맥질환",week:11,order:2,goals:["심장박동장애의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"이숙경(순천제일대학교)"},{id:23,title:"염증성심질환",week:12,order:1,goals:["염증성심장질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"이숙경(순천제일대학교)"},{id:24,title:"판막질환",week:12,order:2,goals:["판막질환의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"이숙경(순천제일대학교)"},{id:25,title:"심근병증",week:13,order:1,goals:["심근병증의 병태생리와 증상을 이해하고 간호를 설명할 수 있다."],instructor:"이숙경(순천제일대학교)"},{id:26,title:"심장수술 대상자 간호",week:13,order:2,goals:["심장수술 대상자를 위한 간호를 설명할 수 있다."],instructor:"이숙경(순천제일대학교)"}],Dr=()=>{const{t:n}=gs("lms"),{uuid:l}=ui(),h=mi(),[d,v]=hi(),{user:r}=pi(),[i,y]=t.useState(!0),[T,$]=t.useState(rr),[F,A]=t.useState(""),[N,b]=t.useState([]),[k,w]=t.useState(null),[p,K]=t.useState(null);T.reduce((U,re)=>(U[re.week]||(U[re.week]=[]),U[re.week].push(re),U),{});const[Z,Q]=t.useState(null),[g,B]=t.useState(""),[W,O]=t.useState(n("courseHome.schedule.weekUnit")),[G,u]=t.useState(n("courseHome.schedule.lessonUnit")),[q,H]=t.useState(!1),[Y,pe]=t.useState(!1),[ye,C]=t.useState(n("courseHome.schedule.weekUnit")),[o,z]=t.useState(n("courseHome.schedule.lessonUnit")),[R,m]=t.useState(!1),[J,ve]=t.useState(""),[xe,Ie]=t.useState(null),[oe,ee]=t.useState(null),[de,Te]=t.useState(!1),Ze=fs.useCallback(async()=>{try{const U=await I.getCWSItem(l);Ve(U)}catch(U){console.error("Failed to refresh course data:",U)}window.dispatchEvent(new CustomEvent("syllabusUpdated"))},[l]),[ue,$e]=t.useState(!1),[Oe,Ve]=t.useState(null),[Ge,Pe]=t.useState(null);t.useEffect(()=>{if(!l)return;let U=!0;return I.getLearningWindow(l).then(re=>{U&&Pe(re)}).catch(()=>{}),()=>{U=!1}},[l]);const[me,Re]=t.useState(!1),[Ye,nt]=t.useState(null),[Pt,Le]=t.useState(!1),[_,L]=t.useState(!1),[X,M]=t.useState([]),[ae,x]=t.useState(!1),[ge,te]=t.useState(!1);t.useEffect(()=>{(async()=>
12{if(l)try{const re=await I.getCWSItem(l);if(A(re.title||""),Ve(re),!r){Re(!1);return}if(r.role==="admin")Re(!0);else try{if(((await Ce.get("/lms/instructors/my-courses")).data.courses||[]).some(Ke=>Ke.cw_uuid===l))Re(!0);else if(xi(r)){const Ke=r.user_ins_id,Rt=re.institution_id||re.ins_id;Re(!!(Ke&&Rt&&Ke===Rt))}else Re(!1)}catch(se){console.error("Failed to check instructor status:",se),Re(!1)}try{const se=await Ce.get(`/lms/cws-notices/${l}/all`);b((se.data.items||[]).slice(0,5))}catch(se){console.error("Failed to load course notices:",se),b([])}try{const se=await I.getRegistrationStatus(l);nt(se)}catch(se){console.error("Failed to load registration status:",se),nt(null)}finally{te(!0)}}catch(re){console.error("Failed to load course data:",re),te(!0)}})()},[l,r]),t.useEffect(()=>{if(!l)return;let U=!1;return Ce.get(`/lms/cohort/${l}`).then(re=>{U||(M(re.data?.items||[]),x(!0))}).catch(()=>{U||x(!0)}),()=>{U=!0}},[l]),t.useEffect(()=>{if(!l||!ae||!ge||d.get("cohort"))return;const U=X.length>0?X[0].cohort_id||`${l}_${X[0].cohort_number}`:"",re=Ye?.cohort_id||U;if(re){const se=new URLSearchParams(d);se.set("cohort",re),v(se,{replace:!0})}},[l,ae,ge,X,Ye,d,v]);const Ee=()=>{if(!l)return;const U=`last_learning_${l}`,re=localStorage.getItem(U);if(re)try{const se=JSON.parse(re),{blockId:Be,blockType:ze}=se;Ie(Be),ee(ze);const Ke=new CustomEvent("openLastLearningBlock",{detail:{blockId:Be,blockType:ze}});window.dispatchEvent(Ke)}catch(se){console.error("Failed to parse last learning data:",se),alert(n("courseHome.learningList.noLastPosition"))}else alert(n("courseHome.learningList.noLastRecord"))},qe=async()=>{if(!(!l||!Ye?.cohort_id)){L(!0);try{await I.cancelRegistration(l,Ye.cohort_id),alert(n("courseHome.learningList.cancelSuccess","수강이 취소되었습니다.")),Le(!1),h("/lms/home")}catch(U){console.error("Failed to cancel registration:",U),alert(n("courseHome.learningList.cancelError","수강 취소에 실패했습니다."))}finally{L(!1)}}},we=U=>{};return e.jsxs(gi,{children:[F&&e.jsx("header",{style:{width:"100%",marginBottom:"24px",paddingBottom:"16px",borderBottom:"2px solid #1E4199"},children:e.jsxs("h1",{style:{fontSize:"28px",fontWeight:"600",color:"#333333",fontFamily:"Pretendard-SemiBold, Helvetica",margin:"0"},children:[F,(()=>{const U=d.get("cohort"),re=X.find(se=>(se.cohort_id||`${l}_${se.cohort_number}`)===U);return me&&X.length>=1?e.jsx("select",{value:U||"",onChange:se=>{const Be=new URLSearchParams(d);Be.set("cohort",se.target.value),v(Be,{replace:!0})},style:{marginLeft:"12px",padding:"4px 10px",fontSize:"15px",fontWeight:400,color:"#333333",border:"1px solid #d1d5db",borderRadius:"6px",background:"#fff",verticalAlign:"middle"},title:"기수 선택",children:X.map(se=>{const Be=se.cohort_id||`${l}_${se.cohort_number}`;return e.jsx("option",{value:Be,children:se.name||`${se.cohort_number}기`},Be)})}):re&&X.length>=2?e.jsxs("span",{style:{fontSize:"20px",fontWeight:"400",color:"#666666",marginLeft:"8px"},children:["(",re.name,")"]}):null})()]})}),Ge?.open===!1&&e.jsxs("div",{className:"course-review-only",role:"status",children:[e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[e.jsx("circle",{cx:"12",cy:"12",r:"10"}),e.jsx("line",{x1:"12",y1:"8",x2:"12",y2:"12"}),e.jsx("line",{x1:"12",y1:"16",x2:"12.01",y2:"16"})]}),e.jsxs("div",{children:[e.jsx("b",{children:Ge.state==="before"?"아직 학습 기간이 아닙니다.":"복습만 가능한 강좌입니다."}),e.jsx("p",{children:Ge.message})]})]}),e.jsxs("div",{className:"course-home-container",children:[e.jsx(vi,{uuid:l}),e.jsxs("div",{className:"course-main-content",children:[e.jsx("div",{className:"dashboard",children:e.jsxs("div",{className:"dashboard__block",children:[e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[e.jsxs("h2",{className:"subTitleAll",style:{margin:0},children:[e.jsx("img",{src:"/lmsicons/Home_Bullet.svg",alt:"bullet",style:{width:"14px",height:"14px",marginRight:"8px"}}),n("courseHome.notice.title")]}),e.jsxs("button",{onClick:()=>h(`/lms/cws/home/${l}/notice${d.get("cohort")?`?cohort=${d.get("cohort")}`:""}`),style:{background:"none",border:"none",color:"#1E4199",cursor:"pointer",fontSize:"13px",fontFamily:"Pretendard-Medium, Helvetica"},children:[n("courseHome.notice.more")," >"]})]}),e.jsx("div",{className:"dashboard__block",children:e.jsx("div",{className:"dashboard__notice",style:{marginTop:"12px"},children:e.jsx("div",{className:"box",style:{padding:"12px"},children:e.jsx("div",{className:"box__body",children:e.jsx("div",{className:"box__noticeList",children:N.length>0?e.jsx("ul",{className:"notice-list",children:N.map(U=>e.jsxs("li",{className:`notice-item${U.read===!1?" notice-unread":""}`,onClick:()=>h(U.kind==="block"?`/lms/cws/home/${l}?block=${encodeURIComponent(U.id)}${d.get("cohort")?`&cohort=${d.get("cohort")}`:""}`:`/lms/cws/home/${l}/notice/${U.id}`),children:[(U.pinned??U.notices)&&e.jsx("span",{className:"notice-badge",children:n("courseHome.notice.pinned")}),U.read===!1&&e.jsx("span",{className:"notice-new",title:"아직 읽지 않았습니다",children:"N"}),e.jsx("span",{className:"notice-title",children:U.title}),e.jsx("span",{className:"notice-date",children:(()=>{const re=Lt(U.created_at||U.published_at);return re?re.toLocaleDateString("ko-KR",{year:"numeric",month:"2-digit",day:"2-digit",timeZone:"Asia/Seoul"}).replace(/\s/g,""):""})()})]},U.key||U.id))}):e.jsx("div",{className:"blank",style:{padding:"8px 0",fontSize:"14px"}
12,children:n("courseHome.notice.noNotice")})})})})})}),!1]})}),e.jsx("div",{className:"lecturePlan__col studydashboardBottom",children:e.jsxs("div",{className:"lecturePlan__content",children:[e.jsxs("div",{className:"learning-list-header",children:[e.jsxs("h2",{className:"subTitleAll",style:{margin:0},children:[e.jsx("img",{src:"/lmsicons/Home_Bullet.svg",alt:"bullet",style:{width:"14px",height:"14px",marginRight:"8px"}}),n("courseHome.learningList.title")]}),e.jsxs("div",{className:"learning-list-buttons desktop-only",children:[me&&e.jsxs("button",{className:"edit-syllabus-btn",onClick:()=>$e(!0),children:[e.jsx("img",{src:"/lmsicons/course-menu/강의정보/강의계획서.svg",alt:n("courseHome.learningList.edit")}),n("courseHome.learningList.edit")]}),Ye?.is_registered&&e.jsx("button",{className:"cancel-registration-btn",onClick:()=>Le(!0),children:n("courseHome.learningList.cancelRegistration","수강 취소")}),e.jsxs("button",{className:"continue-learning-btn",onClick:Ee,children:[e.jsx("img",{src:"/lmsicons/course-menu/강의정보/강의계획서.svg",alt:n("courseHome.learningList.continueLearning")}),n("courseHome.learningList.continueLearning")]})]})]}),e.jsxs("div",{className:"learning-list-buttons mobile-only",children:[e.jsxs("button",{className:"continue-learning-btn",onClick:Ee,children:[e.jsx("img",{src:"/lmsicons/course-menu/강의정보/강의계획서.svg",alt:n("courseHome.learningList.continueLearning")}),n("courseHome.learningList.continueLearning")]}),me&&e.jsxs("button",{className:"edit-syllabus-btn",onClick:()=>$e(!0),children:[e.jsx("img",{src:"/lmsicons/course-menu/강의정보/강의계획서.svg",alt:n("courseHome.learningList.edit")}),n("courseHome.learningList.edit")]}),Ye?.is_registered&&e.jsx("button",{className:"cancel-registration-btn",onClick:()=>Le(!0),children:n("courseHome.learningList.cancelRegistration","수강 취소")})]}),e.jsx(ir,{cwUuid:l,cohortId:d.get("cohort")||void 0})]})})]})]}),e.jsx(Ci,{isOpen:R,onClose:()=>m(!1),onSubmit:we,lessonId:J}),ue&&Oe&&e.jsx("div",{className:"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50",children:e.jsx("div",{className:"bg-white rounded-lg w-full max-w-7xl max-h-[95vh] overflow-hidden flex flex-col",children:e.jsx(Si,{cws:Oe,onClose:()=>{$e(!1),Ze()},onSave:Ze})})}),e.jsx(Ti,{isOpen:de,onClose:()=>Te(!1),cwUuid:l,onSuccess:()=>{window.dispatchEvent(new CustomEvent("attendanceCreated"))}}),Pt&&e.jsx("div",{className:"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50",children:e.jsxs("div",{className:"bg-white rounded-lg p-6 max-w-md w-full mx-4",children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",style:{color:"#333"},children:n("courseHome.learningList.cancelConfirmTitle","수강 취소")}),e.jsx("p",{className:"text-gray-600 mb-6",children:n("courseHome.learningList.cancelConfirmMessage","정말로 이 강좌의 수강을 취소하시겠습니까? 수강 취소 후에는 학습 기록이 삭제될 수 있습니다.")}),e.jsxs("div",{className:"flex justify-end gap-3",children:[e.jsx("button",{onClick:()=>Le(!1),disabled:_,style:{padding:"8px 16px",backgroundColor:"#e5e7eb",color:"#374151",border:"none",borderRadius:"4px",cursor:_?"not-allowed":"pointer",fontSize:"14px",fontWeight:"500"},children:n("common.cancel","취소")}),e.jsx("button",{onClick:qe,disabled:_,style:{padding:"8px 16px",backgroundColor:"#dc2626",color:"white",border:"none",borderRadius:"4px",cursor:_?"not-allowed":"pointer",fontSize:"14px",fontWeight:"500",opacity:_?.7:1},children:_?n("common.processing","처리 중..."):n("courseHome.learningList.confirmCancel","수강 취소")})]})]})})]})};export{Dr 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.