강좌 삭제 구현1
This commit is contained in:
@@ -26,13 +26,16 @@ export default function LessonEditPage() {
|
||||
const [courseVideoCount, setCourseVideoCount] = useState(0);
|
||||
const [courseVideoFiles, setCourseVideoFiles] = useState<string[]>([]);
|
||||
const [courseVideoFileObjects, setCourseVideoFileObjects] = useState<File[]>([]);
|
||||
const [courseVideoFileKeys, setCourseVideoFileKeys] = useState<string[]>([]);
|
||||
const [existingVideoFiles, setExistingVideoFiles] = useState<Array<{fileName: string, fileKey?: string, url?: string}>>([]);
|
||||
const [vrContentCount, setVrContentCount] = useState(0);
|
||||
const [vrContentFiles, setVrContentFiles] = useState<string[]>([]);
|
||||
const [vrContentFileObjects, setVrContentFileObjects] = useState<File[]>([]);
|
||||
const [vrContentFileKeys, setVrContentFileKeys] = useState<string[]>([]);
|
||||
const [existingVrFiles, setExistingVrFiles] = useState<Array<{fileName: string, fileKey?: string, url?: string}>>([]);
|
||||
const [questionFileCount, setQuestionFileCount] = useState(0);
|
||||
const [questionFileObject, setQuestionFileObject] = useState<File | null>(null);
|
||||
const [questionFileKey, setQuestionFileKey] = useState<string | null>(null);
|
||||
const [existingQuestionFile, setExistingQuestionFile] = useState<{fileName: string, fileKey?: string} | null>(null);
|
||||
|
||||
// 원본 데이터 저장 (변경사항 비교용)
|
||||
@@ -271,61 +274,41 @@ export default function LessonEditPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 새로 업로드된 파일들 처리
|
||||
// 이미 업로드된 fileKey 배열 사용
|
||||
let videoUrl: string | undefined;
|
||||
let webglUrl: string | undefined;
|
||||
let csvUrl: string | undefined;
|
||||
|
||||
// 강좌 영상 업로드 (새 파일이 있는 경우)
|
||||
if (courseVideoFileObjects.length > 0) {
|
||||
try {
|
||||
const uploadResponse = await apiService.uploadFiles(courseVideoFileObjects);
|
||||
// 다중 파일 업로드 응답 처리 (실제 API 응답 구조에 맞게 조정 필요)
|
||||
if (uploadResponse.data && uploadResponse.data.length > 0) {
|
||||
videoUrl = uploadResponse.data[0].url || uploadResponse.data[0].fileKey;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('강좌 영상 업로드 실패:', error);
|
||||
throw new Error('강좌 영상 업로드에 실패했습니다.');
|
||||
}
|
||||
// 강좌 영상 fileKey (새로 업로드된 파일이 있는 경우)
|
||||
if (courseVideoFileKeys.length > 0) {
|
||||
videoUrl = courseVideoFileKeys[0]; // 첫 번째 fileKey 사용
|
||||
// TODO: API가 배열을 받는 경우 courseVideoFileKeys 배열 전체를 저장해야 함
|
||||
} else if (existingVideoFiles.length > 0 && existingVideoFiles[0].url) {
|
||||
// 기존 파일 URL 유지
|
||||
videoUrl = existingVideoFiles[0].url;
|
||||
} else if (existingVideoFiles.length > 0 && existingVideoFiles[0].fileKey) {
|
||||
// 기존 파일 fileKey 사용
|
||||
videoUrl = existingVideoFiles[0].fileKey;
|
||||
}
|
||||
|
||||
// VR 콘텐츠 업로드 (새 파일이 있는 경우)
|
||||
if (vrContentFileObjects.length > 0) {
|
||||
try {
|
||||
const uploadResponse = await apiService.uploadFiles(vrContentFileObjects);
|
||||
if (uploadResponse.data && uploadResponse.data.length > 0) {
|
||||
webglUrl = uploadResponse.data[0].url || uploadResponse.data[0].fileKey;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('VR 콘텐츠 업로드 실패:', error);
|
||||
throw new Error('VR 콘텐츠 업로드에 실패했습니다.');
|
||||
}
|
||||
// VR 콘텐츠 fileKey (새로 업로드된 파일이 있는 경우)
|
||||
if (vrContentFileKeys.length > 0) {
|
||||
webglUrl = vrContentFileKeys[0]; // 첫 번째 fileKey 사용
|
||||
// TODO: API가 배열을 받는 경우 vrContentFileKeys 배열 전체를 저장해야 함
|
||||
} else if (existingVrFiles.length > 0 && existingVrFiles[0].url) {
|
||||
// 기존 파일 URL 유지
|
||||
webglUrl = existingVrFiles[0].url;
|
||||
} else if (existingVrFiles.length > 0 && existingVrFiles[0].fileKey) {
|
||||
// 기존 파일 fileKey 사용
|
||||
webglUrl = existingVrFiles[0].fileKey;
|
||||
}
|
||||
|
||||
// 학습 평가 문제 업로드 (새 파일이 있는 경우)
|
||||
if (questionFileObject) {
|
||||
try {
|
||||
const uploadResponse = await apiService.uploadFile(questionFileObject);
|
||||
const fileKey = uploadResponse.data?.key || uploadResponse.data?.fileKey || uploadResponse.data?.csvKey;
|
||||
if (fileKey) {
|
||||
csvUrl = `csv/${fileKey}`;
|
||||
} else if (uploadResponse.data?.url) {
|
||||
csvUrl = uploadResponse.data.url;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('학습 평가 문제 업로드 실패:', error);
|
||||
throw new Error('학습 평가 문제 업로드에 실패했습니다.');
|
||||
}
|
||||
// 학습 평가 문제 fileKey (새로 업로드된 파일이 있는 경우)
|
||||
if (questionFileKey) {
|
||||
csvUrl = questionFileKey;
|
||||
} else if (existingQuestionFile?.fileKey) {
|
||||
// 기존 파일 URL 유지
|
||||
csvUrl = `csv/${existingQuestionFile.fileKey}`;
|
||||
// 기존 파일 fileKey 사용
|
||||
csvUrl = existingQuestionFile.fileKey;
|
||||
} else if (originalData.csvUrl) {
|
||||
// 원본 데이터의 csvUrl 유지
|
||||
csvUrl = originalData.csvUrl;
|
||||
@@ -634,36 +617,74 @@ export default function LessonEditPage() {
|
||||
if (!files) return;
|
||||
|
||||
const MAX_SIZE = 30 * 1024 * 1024; // 30MB
|
||||
const MAX_COUNT = 10; // 최대 10개
|
||||
const validFiles: File[] = [];
|
||||
const oversizedFiles: string[] = [];
|
||||
const invalidTypeFiles: string[] = [];
|
||||
|
||||
Array.from(files).forEach((file) => {
|
||||
// mp4 파일인지 확인
|
||||
if (!file.name.toLowerCase().endsWith('.mp4')) {
|
||||
invalidTypeFiles.push(file.name);
|
||||
return;
|
||||
}
|
||||
if (file.size < MAX_SIZE) {
|
||||
// 각 파일이 30MB 이하인지 검사
|
||||
if (file.size <= MAX_SIZE) {
|
||||
validFiles.push(file);
|
||||
} else {
|
||||
oversizedFiles.push(file.name);
|
||||
}
|
||||
});
|
||||
|
||||
if (oversizedFiles.length > 0) {
|
||||
alert(`다음 파일은 30MB 미만이어야 합니다:\n${oversizedFiles.join('\n')}`);
|
||||
// 파일 타입 오류
|
||||
if (invalidTypeFiles.length > 0) {
|
||||
alert(`다음 파일은 MP4 형식만 가능합니다:\n${invalidTypeFiles.join('\n')}`);
|
||||
}
|
||||
|
||||
if (existingVideoFiles.length + courseVideoFiles.length + validFiles.length > 10) {
|
||||
alert('강좌 영상은 최대 10개까지 첨부할 수 있습니다.');
|
||||
// 30MB 초과 파일이 있으면 알림
|
||||
if (oversizedFiles.length > 0) {
|
||||
alert(`다음 파일은 30MB 이하여야 합니다:\n${oversizedFiles.join('\n')}`);
|
||||
}
|
||||
|
||||
// 파일 개수 제한 확인
|
||||
const totalCount = existingVideoFiles.length + courseVideoFiles.length + validFiles.length;
|
||||
if (totalCount > MAX_COUNT) {
|
||||
const currentCount = existingVideoFiles.length + courseVideoFiles.length;
|
||||
const availableCount = MAX_COUNT - currentCount;
|
||||
alert(`강좌 영상은 최대 ${MAX_COUNT}개까지 첨부할 수 있습니다. (현재 ${currentCount}개, 추가 가능 ${availableCount > 0 ? availableCount : 0}개)`);
|
||||
e.target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 30MB 초과 파일이나 잘못된 타입 파일만 있는 경우 중단
|
||||
if (validFiles.length === 0 && (oversizedFiles.length > 0 || invalidTypeFiles.length > 0)) {
|
||||
e.target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
try {
|
||||
await apiService.uploadFiles(validFiles);
|
||||
setCourseVideoFiles(prev => [...prev, ...validFiles.map(f => f.name)]);
|
||||
setCourseVideoFileObjects(prev => [...prev, ...validFiles]);
|
||||
setCourseVideoCount(prev => prev + validFiles.length);
|
||||
// 다중 파일 업로드
|
||||
const uploadResponse = await apiService.uploadFiles(validFiles);
|
||||
|
||||
// 응답에서 fileKey 배열 추출
|
||||
const fileKeys: string[] = [];
|
||||
if (uploadResponse.data?.results && Array.isArray(uploadResponse.data.results)) {
|
||||
uploadResponse.data.results.forEach((result: any) => {
|
||||
if (result.ok && result.fileKey) {
|
||||
fileKeys.push(result.fileKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (fileKeys.length > 0) {
|
||||
setCourseVideoFiles(prev => [...prev, ...validFiles.map(f => f.name)]);
|
||||
setCourseVideoFileObjects(prev => [...prev, ...validFiles]);
|
||||
setCourseVideoFileKeys(prev => [...prev, ...fileKeys]);
|
||||
setCourseVideoCount(prev => prev + validFiles.length);
|
||||
} else {
|
||||
throw new Error('파일 업로드는 완료되었지만 fileKey를 받지 못했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('강좌 영상 업로드 실패:', error);
|
||||
alert('파일 업로드에 실패했습니다. 다시 시도해주세요.');
|
||||
@@ -717,6 +738,7 @@ export default function LessonEditPage() {
|
||||
onClick={() => {
|
||||
setCourseVideoFiles(prev => prev.filter((_, i) => i !== index));
|
||||
setCourseVideoFileObjects(prev => prev.filter((_, i) => i !== index));
|
||||
setCourseVideoFileKeys(prev => prev.filter((_, i) => i !== index));
|
||||
setCourseVideoCount(prev => prev - 1);
|
||||
}}
|
||||
className="size-[16px] flex items-center justify-center cursor-pointer hover:opacity-70 transition-opacity shrink-0"
|
||||
@@ -754,36 +776,74 @@ export default function LessonEditPage() {
|
||||
if (!files) return;
|
||||
|
||||
const MAX_SIZE = 30 * 1024 * 1024; // 30MB
|
||||
const MAX_COUNT = 10; // 최대 10개
|
||||
const validFiles: File[] = [];
|
||||
const oversizedFiles: string[] = [];
|
||||
const invalidTypeFiles: string[] = [];
|
||||
|
||||
Array.from(files).forEach((file) => {
|
||||
// zip 파일인지 확인
|
||||
if (!file.name.toLowerCase().endsWith('.zip')) {
|
||||
invalidTypeFiles.push(file.name);
|
||||
return;
|
||||
}
|
||||
if (file.size < MAX_SIZE) {
|
||||
// 각 파일이 30MB 이하인지 검사
|
||||
if (file.size <= MAX_SIZE) {
|
||||
validFiles.push(file);
|
||||
} else {
|
||||
oversizedFiles.push(file.name);
|
||||
}
|
||||
});
|
||||
|
||||
if (oversizedFiles.length > 0) {
|
||||
alert(`다음 파일은 30MB 미만이어야 합니다:\n${oversizedFiles.join('\n')}`);
|
||||
// 파일 타입 오류
|
||||
if (invalidTypeFiles.length > 0) {
|
||||
alert(`다음 파일은 ZIP 형식만 가능합니다:\n${invalidTypeFiles.join('\n')}`);
|
||||
}
|
||||
|
||||
if (existingVrFiles.length + vrContentFiles.length + validFiles.length > 10) {
|
||||
alert('VR 콘텐츠는 최대 10개까지 첨부할 수 있습니다.');
|
||||
// 30MB 초과 파일이 있으면 알림
|
||||
if (oversizedFiles.length > 0) {
|
||||
alert(`다음 파일은 30MB 이하여야 합니다:\n${oversizedFiles.join('\n')}`);
|
||||
}
|
||||
|
||||
// 파일 개수 제한 확인
|
||||
const totalCount = existingVrFiles.length + vrContentFiles.length + validFiles.length;
|
||||
if (totalCount > MAX_COUNT) {
|
||||
const currentCount = existingVrFiles.length + vrContentFiles.length;
|
||||
const availableCount = MAX_COUNT - currentCount;
|
||||
alert(`VR 콘텐츠는 최대 ${MAX_COUNT}개까지 첨부할 수 있습니다. (현재 ${currentCount}개, 추가 가능 ${availableCount > 0 ? availableCount : 0}개)`);
|
||||
e.target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 30MB 초과 파일이나 잘못된 타입 파일만 있는 경우 중단
|
||||
if (validFiles.length === 0 && (oversizedFiles.length > 0 || invalidTypeFiles.length > 0)) {
|
||||
e.target.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
try {
|
||||
await apiService.uploadFiles(validFiles);
|
||||
setVrContentFiles(prev => [...prev, ...validFiles.map(f => f.name)]);
|
||||
setVrContentFileObjects(prev => [...prev, ...validFiles]);
|
||||
setVrContentCount(prev => prev + validFiles.length);
|
||||
// 다중 파일 업로드
|
||||
const uploadResponse = await apiService.uploadFiles(validFiles);
|
||||
|
||||
// 응답에서 fileKey 배열 추출
|
||||
const fileKeys: string[] = [];
|
||||
if (uploadResponse.data?.results && Array.isArray(uploadResponse.data.results)) {
|
||||
uploadResponse.data.results.forEach((result: any) => {
|
||||
if (result.ok && result.fileKey) {
|
||||
fileKeys.push(result.fileKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (fileKeys.length > 0) {
|
||||
setVrContentFiles(prev => [...prev, ...validFiles.map(f => f.name)]);
|
||||
setVrContentFileObjects(prev => [...prev, ...validFiles]);
|
||||
setVrContentFileKeys(prev => [...prev, ...fileKeys]);
|
||||
setVrContentCount(prev => prev + validFiles.length);
|
||||
} else {
|
||||
throw new Error('파일 업로드는 완료되었지만 fileKey를 받지 못했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('VR 콘텐츠 업로드 실패:', error);
|
||||
alert('파일 업로드에 실패했습니다. 다시 시도해주세요.');
|
||||
@@ -837,6 +897,7 @@ export default function LessonEditPage() {
|
||||
onClick={() => {
|
||||
setVrContentFiles(prev => prev.filter((_, i) => i !== index));
|
||||
setVrContentFileObjects(prev => prev.filter((_, i) => i !== index));
|
||||
setVrContentFileKeys(prev => prev.filter((_, i) => i !== index));
|
||||
setVrContentCount(prev => prev - 1);
|
||||
}}
|
||||
className="size-[16px] flex items-center justify-center cursor-pointer hover:opacity-70 transition-opacity shrink-0"
|
||||
@@ -876,10 +937,30 @@ export default function LessonEditPage() {
|
||||
const file = files[0];
|
||||
if (file.name.toLowerCase().endsWith('.csv')) {
|
||||
try {
|
||||
await apiService.uploadFile(file);
|
||||
setQuestionFileObject(file);
|
||||
setQuestionFileCount(1);
|
||||
setExistingQuestionFile(null);
|
||||
// 단일 파일 업로드
|
||||
const uploadResponse = await apiService.uploadFile(file);
|
||||
|
||||
// 응답에서 fileKey 추출
|
||||
let fileKey: string | null = null;
|
||||
if (uploadResponse.data?.fileKey) {
|
||||
fileKey = uploadResponse.data.fileKey;
|
||||
} else if (uploadResponse.data?.key) {
|
||||
fileKey = uploadResponse.data.key;
|
||||
} else if (uploadResponse.data?.results && Array.isArray(uploadResponse.data.results) && uploadResponse.data.results.length > 0) {
|
||||
const result = uploadResponse.data.results[0];
|
||||
if (result.ok && result.fileKey) {
|
||||
fileKey = result.fileKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (fileKey) {
|
||||
setQuestionFileObject(file);
|
||||
setQuestionFileKey(fileKey);
|
||||
setQuestionFileCount(1);
|
||||
setExistingQuestionFile(null);
|
||||
} else {
|
||||
throw new Error('파일 업로드는 완료되었지만 fileKey를 받지 못했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('학습 평가 문제 업로드 실패:', error);
|
||||
alert('파일 업로드에 실패했습니다. 다시 시도해주세요.');
|
||||
@@ -900,6 +981,7 @@ export default function LessonEditPage() {
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setQuestionFileObject(null);
|
||||
setQuestionFileKey(null);
|
||||
setExistingQuestionFile(null);
|
||||
setQuestionFileCount(0);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user