11"use client" ;
22
3- import { useState , useRef , useMemo , useEffect } from "react" ;
3+ import { useState , useMemo , useEffect } from "react" ;
44import { useRouter , useParams } from "next/navigation" ;
55import styles from "./LectureLiveHeader.module.scss" ;
66import FitContentButton from "@/components/Button/FitContentButton/FitContentButton" ;
7- import IconButton from "@/components/Button/IconButton/IconButton" ;
87import { DocumentSideButtonConnected } from "../DocumentSideButton/DocumentSideButton" ;
98import PenToolButtons from "../PenTool/PenToolButtons/PenToolButtons" ;
109import { useLive } from "../LectureLiveProvider" ;
11- import { FileText } from "lucide-react" ;
12- import ToolPopover from "../ToolPopover/ToolPopover" ;
13- import LectureNotePopover from "../LectureNote/LectureNotePopover/LectureNotePopover" ;
1410import ChatingButton from "../Chating/ChatingButton/ChatingButton" ;
1511import RecordingButton from "../Recording/RecordingButton/RecordingButton" ;
1612import ConfirmModal from "@/components/Modal/ConfirmModal/ConfirmModal" ;
1713import { getRecordingEngine , type RecState } from "../Recording/recordingEngine" ;
1814import { ROUTES } from "@/constants/routes" ;
1915import { Tool } from "../LectureLiveProvider" ;
16+ import LectureNoteButton from "../LectureNote/LectureNoteButton/LectureNoteButton" ;
17+ import { saveAudioFile } from "@/api/lectures/saveAudioFile" ;
2018
2119export default function LectureLiveHeader ( {
2220 onToggleChat,
@@ -28,10 +26,10 @@ export default function LectureLiveHeader({
2826 onEndLecture ?: ( ) => void ;
2927} ) {
3028 const { tool, setTool } = useLive ( ) ;
31- const docBtnRef = useRef < HTMLSpanElement > ( null ) ;
32- const [ openDoc , setOpenDoc ] = useState ( false ) ;
3329
3430 const [ endOpen , setEndOpen ] = useState ( false ) ;
31+ const [ saving , setSaving ] = useState ( false ) ;
32+
3533
3634 const engine = useMemo ( ( ) => getRecordingEngine ( ) , [ ] ) ;
3735 const [ recState , setRecState ] = useState < RecState > ( engine . getSnapshot ( ) . state ) ;
@@ -56,14 +54,33 @@ export default function LectureLiveHeader({
5654 const handleConfirmEnd = async ( ) => {
5755 if ( isRecording ) {
5856 try {
59- await engine . stop ( ) ;
57+ setSaving ( true ) ;
58+ await new Promise < void > ( ( resolve , reject ) => {
59+ const off = engine . subscribe ( "done" , async ( blob ) => {
60+ try {
61+ if ( lectureId ) {
62+ await saveAudioFile ( lectureId , blob ) ;
63+ console . log ( "🎤 녹음 파일 저장 완료" ) ;
64+ }
65+ off ( ) ;
66+ resolve ( ) ;
67+ } catch ( e ) {
68+ console . error ( "❌ 녹음 파일 저장 실패:" , e ) ;
69+ reject ( e ) ;
70+ }
71+ } ) ;
72+
73+ engine . stop ( ) . catch ( reject ) ;
74+ } ) ;
6075 } catch ( e ) {
61- console . error ( e ) ;
76+ console . error ( "녹음 종료 중 오류:" , e ) ;
77+ } finally {
78+ setSaving ( false ) ;
6279 }
6380 }
81+
6482 setEndOpen ( false ) ;
6583 onEndLecture ?.( ) ;
66-
6784 router . push ( ROUTES . teacherLectureDetail ( lectureId ) ) ;
6885 } ;
6986
@@ -75,23 +92,7 @@ export default function LectureLiveHeader({
7592 < div className = { styles . left } >
7693 < DocumentSideButtonConnected />
7794
78- < span ref = { docBtnRef } className = { styles . docBtnZ } >
79- < IconButton
80- ariaLabel = "문서 불러오기"
81- onClick = { ( ) => setOpenDoc ( ( v ) => ! v ) }
82- icon = { < FileText /> }
83- />
84- </ span >
85-
86- < ToolPopover
87- open = { openDoc }
88- anchorRef = { docBtnRef }
89- onClose = { ( ) => setOpenDoc ( false ) }
90- align = "start"
91- side = "bottom"
92- >
93- < LectureNotePopover onPicked = { ( ) => setOpenDoc ( false ) } />
94- </ ToolPopover >
95+ < LectureNoteButton />
9596
9697 < span className = { styles . divider } />
9798 < PenToolButtons value = { tool } onChange = { selectTool } />
@@ -113,8 +114,14 @@ export default function LectureLiveHeader({
113114 </ div >
114115
115116 { endOpen && (
116- < ConfirmModal onConfirm = { handleConfirmEnd } onClose = { handleCancelEnd } >
117- { isRecording ? (
117+ < ConfirmModal
118+ onConfirm = { handleConfirmEnd }
119+ onClose = { handleCancelEnd }
120+ disableActions = { saving }
121+ >
122+ { saving ? (
123+ < > 녹음 파일 저장 중입니다... ⏳</ >
124+ ) : isRecording ? (
118125 < >
119126 지금 녹음이 진행 중입니다.
120127 < br />
0 commit comments