advance
This commit is contained in:
95
components/teacher/VideoUpload.tsx
Normal file
95
components/teacher/VideoUpload.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
import { toast } from "sonner"; // or use alert()
|
||||
|
||||
interface VideoUploadProps {
|
||||
lessonId: string;
|
||||
currentVideoUrl?: string | null;
|
||||
onUploadComplete: (url: string) => void; // Callback to save to DB
|
||||
}
|
||||
|
||||
export default function VideoUpload({ lessonId, currentVideoUrl, onUploadComplete }: VideoUploadProps) {
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
setUploading(true);
|
||||
setProgress(0);
|
||||
|
||||
const supabase = createBrowserClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||
);
|
||||
|
||||
// Create a unique file path: lesson_id/timestamp_filename
|
||||
const filePath = `${lessonId}/${Date.now()}_${file.name}`;
|
||||
|
||||
const { error } = await supabase.storage
|
||||
.from("courses") // Make sure this bucket exists!
|
||||
.upload(filePath, file, {
|
||||
upsert: true,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
toast.error("Upload failed: " + error.message);
|
||||
setUploading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Public URL
|
||||
const { data: { publicUrl } } = supabase.storage
|
||||
.from("courses")
|
||||
.getPublicUrl(filePath);
|
||||
|
||||
onUploadComplete(publicUrl);
|
||||
setUploading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border border-slate-200 rounded-lg p-6 bg-slate-50">
|
||||
<h3 className="font-medium text-slate-900 mb-2">Video de la Lección</h3>
|
||||
|
||||
{currentVideoUrl ? (
|
||||
<div className="mb-4 aspect-video bg-black rounded-md overflow-hidden relative group">
|
||||
<video src={currentVideoUrl} controls className="w-full h-full" />
|
||||
<div className="absolute inset-0 bg-black/50 hidden group-hover:flex items-center justify-center">
|
||||
<p className="text-white text-sm">Subir otro para reemplazar</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mb-4 aspect-video bg-slate-200 rounded-md flex items-center justify-center text-slate-400">
|
||||
Sin video
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="block w-full">
|
||||
<span className="sr-only">Choose video</span>
|
||||
<input
|
||||
type="file"
|
||||
accept="video/*"
|
||||
onChange={handleUpload}
|
||||
disabled={uploading}
|
||||
className="block w-full text-sm text-slate-500
|
||||
file:mr-4 file:py-2 file:px-4
|
||||
file:rounded-full file:border-0
|
||||
file:text-sm file:font-semibold
|
||||
file:bg-black file:text-white
|
||||
hover:file:bg-slate-800
|
||||
"
|
||||
/>
|
||||
</label>
|
||||
{uploading && (
|
||||
<div className="w-full bg-slate-200 rounded-full h-2 mt-2">
|
||||
<div className="bg-black h-2 rounded-full transition-all" style={{ width: `${progress}%` }}></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user