mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
refactor: change video activity modal UI
This commit is contained in:
parent
ed8783d0ef
commit
3173e6b417
7 changed files with 221 additions and 214 deletions
|
|
@ -3,17 +3,42 @@ import YouTube from 'react-youtube'
|
||||||
import { getActivityMediaDirectory } from '@services/media/media'
|
import { getActivityMediaDirectory } from '@services/media/media'
|
||||||
import { useOrg } from '@components/Contexts/OrgContext'
|
import { useOrg } from '@components/Contexts/OrgContext'
|
||||||
|
|
||||||
function VideoActivity({ activity, course }: { activity: any; course: any }) {
|
interface VideoActivityProps {
|
||||||
|
activity: {
|
||||||
|
activity_sub_type: string
|
||||||
|
activity_uuid: string
|
||||||
|
content: {
|
||||||
|
filename?: string
|
||||||
|
uri?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
course: {
|
||||||
|
course_uuid: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function VideoActivity({ activity, course }: VideoActivityProps) {
|
||||||
const org = useOrg() as any
|
const org = useOrg() as any
|
||||||
const [videoId, setVideoId] = React.useState('')
|
const [videoId, setVideoId] = React.useState('')
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (activity && activity.content && activity.content.uri) {
|
if (activity?.content?.uri) {
|
||||||
var getYouTubeID = require('get-youtube-id');
|
var getYouTubeID = require('get-youtube-id')
|
||||||
setVideoId(getYouTubeID(activity.content.uri))
|
setVideoId(getYouTubeID(activity.content.uri))
|
||||||
}
|
}
|
||||||
}, [activity, org])
|
}, [activity, org])
|
||||||
|
|
||||||
|
const getVideoSrc = () => {
|
||||||
|
if (!activity.content?.filename) return ''
|
||||||
|
return getActivityMediaDirectory(
|
||||||
|
org?.org_uuid,
|
||||||
|
course?.course_uuid,
|
||||||
|
activity.activity_uuid,
|
||||||
|
activity.content.filename,
|
||||||
|
'video'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-w-full px-2 sm:px-4">
|
<div className="w-full max-w-full px-2 sm:px-4">
|
||||||
{activity && (
|
{activity && (
|
||||||
|
|
@ -24,13 +49,7 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
|
||||||
<video
|
<video
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
controls
|
controls
|
||||||
src={getActivityMediaDirectory(
|
src={getVideoSrc()}
|
||||||
org?.org_uuid,
|
|
||||||
course?.course_uuid,
|
|
||||||
activity.activity_uuid,
|
|
||||||
activity.content?.filename,
|
|
||||||
'video'
|
|
||||||
)}
|
|
||||||
></video>
|
></video>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -44,7 +63,7 @@ function VideoActivity({ activity, course }: { activity: any; course: any }) {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
playerVars: {
|
playerVars: {
|
||||||
autoplay: 0,
|
autoplay: 0
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
videoId={videoId}
|
videoId={videoId}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ import VideoPageActivityImage from 'public//activities_types/video-page-activity
|
||||||
import DocumentPdfPageActivityImage from 'public//activities_types/documentpdf-page-activity.png'
|
import DocumentPdfPageActivityImage from 'public//activities_types/documentpdf-page-activity.png'
|
||||||
import AssignmentActivityImage from 'public//activities_types/assignment-page-activity.png'
|
import AssignmentActivityImage from 'public//activities_types/assignment-page-activity.png'
|
||||||
|
|
||||||
import DynamicCanvaModal from './NewActivityModal/DynamicCanva'
|
import DynamicCanvaModal from './NewActivityModal/DynamicActivityModal'
|
||||||
import VideoModal from './NewActivityModal/Video'
|
import VideoModal from './NewActivityModal/VideoActivityModal'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import DocumentPdfModal from './NewActivityModal/DocumentPdf'
|
import DocumentPdfModal from './NewActivityModal/DocumentActivityModal'
|
||||||
import Assignment from './NewActivityModal/Assignment'
|
import Assignment from './NewActivityModal/AssignmentActivityModal'
|
||||||
|
|
||||||
function NewActivityModal({
|
function NewActivityModal({
|
||||||
closeModal,
|
closeModal,
|
||||||
|
|
|
||||||
|
|
@ -1,199 +0,0 @@
|
||||||
import FormLayout, {
|
|
||||||
ButtonBlack,
|
|
||||||
Flex,
|
|
||||||
FormField,
|
|
||||||
FormLabel,
|
|
||||||
FormMessage,
|
|
||||||
Input,
|
|
||||||
} from '@components/Objects/StyledElements/Form/Form'
|
|
||||||
import React, { useState } from 'react'
|
|
||||||
import * as Form from '@radix-ui/react-form'
|
|
||||||
import BarLoader from 'react-spinners/BarLoader'
|
|
||||||
import { Youtube } from 'lucide-react'
|
|
||||||
import { constructAcceptValue } from '@/lib/constants';
|
|
||||||
|
|
||||||
const SUPPORTED_FILES = constructAcceptValue(['mp4', 'webm'])
|
|
||||||
|
|
||||||
interface ExternalVideoObject {
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
uri: string
|
|
||||||
chapter_id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
function VideoModal({
|
|
||||||
submitFileActivity,
|
|
||||||
submitExternalVideo,
|
|
||||||
chapterId,
|
|
||||||
course,
|
|
||||||
}: any) {
|
|
||||||
const [video, setVideo] = React.useState(null) as any
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
||||||
const [name, setName] = React.useState('')
|
|
||||||
const [youtubeUrl, setYoutubeUrl] = React.useState('')
|
|
||||||
const [selectedView, setSelectedView] = React.useState('file') as any
|
|
||||||
|
|
||||||
const handleVideoChange = (event: React.ChangeEvent<any>) => {
|
|
||||||
setVideo(event.target.files[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setName(event.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleYoutubeUrlChange = (
|
|
||||||
event: React.ChangeEvent<HTMLInputElement>
|
|
||||||
) => {
|
|
||||||
setYoutubeUrl(event.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = async (e: any) => {
|
|
||||||
e.preventDefault()
|
|
||||||
setIsSubmitting(true)
|
|
||||||
|
|
||||||
if (selectedView === 'file') {
|
|
||||||
let status = await submitFileActivity(
|
|
||||||
video,
|
|
||||||
'video',
|
|
||||||
{
|
|
||||||
name: name,
|
|
||||||
chapter_id: chapterId,
|
|
||||||
activity_type: 'TYPE_VIDEO',
|
|
||||||
activity_sub_type: 'SUBTYPE_VIDEO_HOSTED',
|
|
||||||
published_version: 1,
|
|
||||||
version: 1,
|
|
||||||
course_id: course.id,
|
|
||||||
},
|
|
||||||
chapterId
|
|
||||||
)
|
|
||||||
|
|
||||||
setIsSubmitting(false)
|
|
||||||
}
|
|
||||||
if (selectedView === 'youtube') {
|
|
||||||
let external_video_object: ExternalVideoObject = {
|
|
||||||
name,
|
|
||||||
type: 'youtube',
|
|
||||||
uri: youtubeUrl,
|
|
||||||
chapter_id: chapterId,
|
|
||||||
}
|
|
||||||
|
|
||||||
let status = await submitExternalVideo(
|
|
||||||
external_video_object,
|
|
||||||
'activity',
|
|
||||||
chapterId
|
|
||||||
)
|
|
||||||
setIsSubmitting(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO : implement some sort of progress bar for file uploads, it is not possible yet because i'm not using axios.
|
|
||||||
and the actual upload isn't happening here anyway, it's in the submitFileActivity function */
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormLayout onSubmit={handleSubmit}>
|
|
||||||
<FormField name="video-activity-name">
|
|
||||||
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
|
||||||
<FormLabel>Video name</FormLabel>
|
|
||||||
<FormMessage match="valueMissing">
|
|
||||||
Please provide a name for your video activity
|
|
||||||
</FormMessage>
|
|
||||||
</Flex>
|
|
||||||
<Form.Control asChild>
|
|
||||||
<Input onChange={handleNameChange} type="text" required />
|
|
||||||
</Form.Control>
|
|
||||||
</FormField>
|
|
||||||
<div className="flex flex-col rounded-md bg-gray-50 outline-dashed outline-gray-200">
|
|
||||||
<div className="">
|
|
||||||
<div className="flex m-4 justify-center space-x-2 mb-0">
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedView('file')
|
|
||||||
}}
|
|
||||||
className="rounded-full bg-slate-900 text-zinc-50 py-2 px-4 text-sm drop-shadow-md hover:cursor-pointer hover:bg-slate-700 "
|
|
||||||
>
|
|
||||||
Video upload
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedView('youtube')
|
|
||||||
}}
|
|
||||||
className="rounded-full bg-slate-900 text-zinc-50 py-2 px-4 text-sm drop-shadow-md hover:cursor-pointer hover:bg-slate-700"
|
|
||||||
>
|
|
||||||
YouTube Video
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{selectedView === 'file' && (
|
|
||||||
<div className="p-4 justify-center m-auto align-middle">
|
|
||||||
<FormField name="video-activity-file">
|
|
||||||
<Flex
|
|
||||||
css={{
|
|
||||||
alignItems: 'baseline',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormLabel>Video file</FormLabel>
|
|
||||||
<FormMessage match="valueMissing">
|
|
||||||
Please provide a video for your activity
|
|
||||||
</FormMessage>
|
|
||||||
</Flex>
|
|
||||||
<Form.Control asChild>
|
|
||||||
<input accept={SUPPORTED_FILES} type="file" onChange={handleVideoChange} required />
|
|
||||||
</Form.Control>
|
|
||||||
</FormField>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{selectedView === 'youtube' && (
|
|
||||||
<div className="p-4 justify-center m-auto align-middle">
|
|
||||||
<FormField name="video-activity-file">
|
|
||||||
<Flex
|
|
||||||
css={{
|
|
||||||
alignItems: 'baseline',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormLabel className="flex justify-center align-middle">
|
|
||||||
<Youtube className="m-auto pr-1" />
|
|
||||||
<span className="flex">YouTube URL</span>
|
|
||||||
</FormLabel>
|
|
||||||
<FormMessage match="valueMissing">
|
|
||||||
Please provide a video for your activity
|
|
||||||
</FormMessage>
|
|
||||||
</Flex>
|
|
||||||
<Form.Control asChild>
|
|
||||||
<Input
|
|
||||||
className="bg-white"
|
|
||||||
onChange={handleYoutubeUrlChange}
|
|
||||||
type="text"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</Form.Control>
|
|
||||||
</FormField>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
|
|
||||||
<Form.Submit asChild>
|
|
||||||
<ButtonBlack
|
|
||||||
className="bg-black"
|
|
||||||
type="submit"
|
|
||||||
css={{ marginTop: 10 }}
|
|
||||||
>
|
|
||||||
{isSubmitting ? (
|
|
||||||
<BarLoader
|
|
||||||
cssOverride={{ borderRadius: 60 }}
|
|
||||||
width={60}
|
|
||||||
color="#ffffff"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
'Create activity'
|
|
||||||
)}
|
|
||||||
</ButtonBlack>
|
|
||||||
</Form.Submit>
|
|
||||||
</Flex>
|
|
||||||
</FormLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default VideoModal
|
|
||||||
|
|
@ -0,0 +1,187 @@
|
||||||
|
import FormLayout, {
|
||||||
|
ButtonBlack,
|
||||||
|
Flex,
|
||||||
|
FormField,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
Input,
|
||||||
|
} from '@components/Objects/StyledElements/Form/Form'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import * as Form from '@radix-ui/react-form'
|
||||||
|
import BarLoader from 'react-spinners/BarLoader'
|
||||||
|
import { Youtube, Upload } from 'lucide-react'
|
||||||
|
import { constructAcceptValue } from '@/lib/constants'
|
||||||
|
|
||||||
|
const SUPPORTED_FILES = constructAcceptValue(['mp4', 'webm'])
|
||||||
|
|
||||||
|
interface ExternalVideoObject {
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
uri: string
|
||||||
|
chapter_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function VideoModal({
|
||||||
|
submitFileActivity,
|
||||||
|
submitExternalVideo,
|
||||||
|
chapterId,
|
||||||
|
course,
|
||||||
|
}: any) {
|
||||||
|
const [video, setVideo] = React.useState<File | null>(null)
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
const [name, setName] = React.useState('')
|
||||||
|
const [youtubeUrl, setYoutubeUrl] = React.useState('')
|
||||||
|
const [selectedView, setSelectedView] = React.useState<'file' | 'youtube'>('file')
|
||||||
|
|
||||||
|
const handleVideoChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (event.target.files?.[0]) {
|
||||||
|
setVideo(event.target.files[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
setIsSubmitting(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (selectedView === 'file' && video) {
|
||||||
|
await submitFileActivity(
|
||||||
|
video,
|
||||||
|
'video',
|
||||||
|
{
|
||||||
|
name: name,
|
||||||
|
chapter_id: chapterId,
|
||||||
|
activity_type: 'TYPE_VIDEO',
|
||||||
|
activity_sub_type: 'SUBTYPE_VIDEO_HOSTED',
|
||||||
|
published_version: 1,
|
||||||
|
version: 1,
|
||||||
|
course_id: course.id,
|
||||||
|
},
|
||||||
|
chapterId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedView === 'youtube') {
|
||||||
|
const external_video_object: ExternalVideoObject = {
|
||||||
|
name,
|
||||||
|
type: 'youtube',
|
||||||
|
uri: youtubeUrl,
|
||||||
|
chapter_id: chapterId,
|
||||||
|
}
|
||||||
|
|
||||||
|
await submitExternalVideo(
|
||||||
|
external_video_object,
|
||||||
|
'activity',
|
||||||
|
chapterId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormLayout onSubmit={handleSubmit}>
|
||||||
|
<FormField name="video-activity-name">
|
||||||
|
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
||||||
|
<FormLabel>Activity Name</FormLabel>
|
||||||
|
<FormMessage match="valueMissing">
|
||||||
|
Please provide a name for your video activity
|
||||||
|
</FormMessage>
|
||||||
|
</Flex>
|
||||||
|
<Form.Control asChild>
|
||||||
|
<Input
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
placeholder="Enter activity name..."
|
||||||
|
/>
|
||||||
|
</Form.Control>
|
||||||
|
</FormField>
|
||||||
|
|
||||||
|
<div className="mt-4 rounded-lg border border-gray-200">
|
||||||
|
<div className="grid grid-cols-2 gap-0">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setSelectedView('file')}
|
||||||
|
className={`flex items-center justify-center p-4 gap-2 ${
|
||||||
|
selectedView === 'file'
|
||||||
|
? 'bg-gray-100 border-b-2 border-black'
|
||||||
|
: 'hover:bg-gray-50 border-b border-gray-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Upload size={18} />
|
||||||
|
<span>Upload Video</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setSelectedView('youtube')}
|
||||||
|
className={`flex items-center justify-center p-4 gap-2 ${
|
||||||
|
selectedView === 'youtube'
|
||||||
|
? 'bg-gray-100 border-b-2 border-black'
|
||||||
|
: 'hover:bg-gray-50 border-b border-gray-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Youtube size={18} />
|
||||||
|
<span>YouTube Video</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-6">
|
||||||
|
{selectedView === 'file' && (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<FormField name="video-activity-file">
|
||||||
|
<FormLabel>Video File</FormLabel>
|
||||||
|
<div className="mt-2">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept={SUPPORTED_FILES}
|
||||||
|
onChange={handleVideoChange}
|
||||||
|
required
|
||||||
|
className="w-full text-sm text-gray-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-gray-800"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedView === 'youtube' && (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<FormField name="youtube-url">
|
||||||
|
<FormLabel>YouTube URL</FormLabel>
|
||||||
|
<Form.Control asChild>
|
||||||
|
<Input
|
||||||
|
value={youtubeUrl}
|
||||||
|
onChange={(e) => setYoutubeUrl(e.target.value)}
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
placeholder="https://youtube.com/watch?v=..."
|
||||||
|
/>
|
||||||
|
</Form.Control>
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
|
||||||
|
<Form.Submit asChild>
|
||||||
|
<ButtonBlack type="submit" css={{ marginTop: 10 }}>
|
||||||
|
{isSubmitting ? (
|
||||||
|
<BarLoader
|
||||||
|
cssOverride={{ borderRadius: 60 }}
|
||||||
|
width={60}
|
||||||
|
color="#ffffff"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'Create Activity'
|
||||||
|
)}
|
||||||
|
</ButtonBlack>
|
||||||
|
</Form.Submit>
|
||||||
|
</Flex>
|
||||||
|
</FormLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VideoModal
|
||||||
Loading…
Add table
Add a link
Reference in a new issue