diff --git a/apps/frontend/src/components/launches/helpers/media.settings.component.tsx b/apps/frontend/src/components/launches/helpers/media.settings.component.tsx index 3ce19f2c3..455f086d1 100644 --- a/apps/frontend/src/components/launches/helpers/media.settings.component.tsx +++ b/apps/frontend/src/components/launches/helpers/media.settings.component.tsx @@ -5,7 +5,7 @@ import React, { FC, useCallback, useEffect, useRef, useState } from 'react'; import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store'; -import { useVariables } from '@gitroom/react/helpers/variable.context'; +import { MediaBox } from '../../media/media.component'; const postUrlEmitter = new EventEmitter(); export const MediaSettingsLayout = () => { @@ -98,22 +98,26 @@ export const CreateThumbnail: FC<{ altText?: string; onAltTextChange?: (altText: string) => void; }> = (props) => { - const { onSelect, media } = props; - const { backendUrl } = useVariables(); + const { onSelect, media, altText, onAltTextChange } = props; const videoRef = useRef(null); const canvasRef = useRef(null); + const fileInputRef = useRef(null); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [isLoaded, setIsLoaded] = useState(false); const [isCapturing, setIsCapturing] = useState(false); const handleLoadedMetadata = useCallback(() => { - setDuration(videoRef?.current?.duration); - setIsLoaded(true); + if (videoRef.current) { + setDuration(videoRef.current.duration); + setIsLoaded(true); + } }, []); const handleTimeUpdate = useCallback(() => { - setCurrentTime(videoRef?.current?.currentTime); + if (videoRef.current) { + setCurrentTime(videoRef.current.currentTime); + } }, []); const handleSeek = useCallback((e: React.ChangeEvent) => { @@ -125,6 +129,8 @@ export const CreateThumbnail: FC<{ }, []); const captureFrame = useCallback(async () => { + if (!videoRef.current || !canvasRef.current) return; + setIsCapturing(true); try { @@ -206,6 +212,37 @@ export const CreateThumbnail: FC<{ return `${mins}:${secs.toString().padStart(2, '0')}`; }, []); + const handleFileUpload = useCallback( + (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + if (!file.type.startsWith('image/')) { + alert('Veuillez sélectionner un fichier image valide'); + return; + } + + const reader = new FileReader(); + reader.onload = () => { + const blob = new Blob([file], { type: file.type }); + + onSelect(blob, 0); + }; + reader.readAsArrayBuffer(file); + + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }, + [onSelect] + ); + + const triggerFileInput = useCallback(() => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } + }, []); + if (!media) return null; return ( @@ -213,9 +250,7 @@ export const CreateThumbnail: FC<{
)} @@ -321,6 +370,8 @@ export const MediaComponentInner: FC<{ props.media?.thumbnailTimestamp || null ); + const [showMediaBoxModal, setShowMediaBoxModal] = useState(false); + useEffect(() => { setActivateExitButton(false); return () => { @@ -328,21 +379,47 @@ export const MediaComponentInner: FC<{ }; }, []); + const handleImportThumbnail = useCallback( + (selectedMedia: Array<{ id: string; path: string }>) => { + if (selectedMedia && selectedMedia.length > 0) { + const selected = selectedMedia[0]; + + setNewThumbnail(selected.path); + setThumbnailTimestamp(null); + setShowMediaBoxModal(false); + } + }, + [] + ); + + const openMediaBoxForThumbnail = useCallback(() => { + setShowMediaBoxModal(true); + }, []); + + const closeMediaBoxModal = useCallback(() => { + setShowMediaBoxModal(false); + }, []); + const save = useCallback(async () => { setLoading(true); let path = thumbnail || ''; + if (newThumbnail) { - const blob = await (await fetch(newThumbnail)).blob(); - const formData = new FormData(); - formData.append('file', blob, 'media.jpg'); - formData.append('preventSave', 'true'); - const data = await ( - await newFetch('/media/upload-simple', { - method: 'POST', - body: formData, - }) - ).json(); - path = data.path; + if (newThumbnail.startsWith('blob:')) { + const blob = await (await fetch(newThumbnail)).blob(); + const formData = new FormData(); + formData.append('file', blob, 'media.jpg'); + formData.append('preventSave', 'true'); + const data = await ( + await newFetch('/media/upload-simple', { + method: 'POST', + body: formData, + }) + ).json(); + path = data.path; + } else { + path = newThumbnail; + } } const media = await ( @@ -362,132 +439,176 @@ export const MediaComponentInner: FC<{ }, [altText, newThumbnail, thumbnail, thumbnailTimestamp]); return ( -
-
- - setAltText(e.target.value)} - placeholder="Describe the image/video content..." - className="w-full px-3 py-2 bg-fifth border border-tableBorder rounded-lg text-textColor placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-forth focus:border-transparent" +
+ {showMediaBoxModal && ( + -
- {media?.path.indexOf('mp4') > -1 && ( - <> - {/* Alt Text Input */} -
- {!isEditingThumbnail ? ( -
- {/* Show existing thumbnail if it exists */} - {(newThumbnail || thumbnail) && ( -
- - Current Thumbnail: - - Current thumbnail -
- )} - - {/* Action Buttons */} -
- - {(thumbnail || newThumbnail) && ( - - )} -
-
- ) : ( -
- {/* Back button */} -
- +
+
+
+ + setAltText(e.target.value)} + placeholder="Describe the image/video content..." + className="w-full px-3 py-2 bg-fifth border border-tableBorder rounded-lg text-textColor placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-forth focus:border-transparent" + /> +
+ {media?.path.indexOf('mp4') > -1 && ( + <> +
+ {!isEditingThumbnail ? ( +
+ {/* Show existing thumbnail if it exists */} + {(newThumbnail || thumbnail) && ( +
+ + Current Thumbnail: + + Current thumbnail +
+ )} + + {/* Action Buttons */} +
+ + {(thumbnail || newThumbnail) && ( + + )} +
+ {/* MODIFICATION: Bouton Import Thumbnail use MediaBox */} + +
+ ) : ( +
+ {/* Back button */} +
+ +
+ + {/* Thumbnail Editor */} + { + const reader = new FileReader(); + reader.onload = () => { + const url = URL.createObjectURL(blob); + setNewThumbnail(url); + setThumbnailTimestamp(timestampMs); + setIsEditingThumbnail(false); + }; + reader.readAsDataURL(blob); + }} + media={media} + altText={altText} + onAltTextChange={setAltText} /> - - Back - +
+ )}
+ + )} - {/* Thumbnail Editor */} - { - // Convert blob to base64 or handle as needed - const reader = new FileReader(); - reader.onload = () => { - // You can handle the result here - for now just call onSelect with the blob URL - const url = URL.createObjectURL(blob); - setNewThumbnail(url); - setThumbnailTimestamp(timestampMs); - setIsEditingThumbnail(false); - }; - reader.readAsDataURL(blob); - }} - media={media} - altText={altText} - onAltTextChange={setAltText} - /> + {!isEditingThumbnail && ( +
+ +
)}
- - )} - - {!isEditingThumbnail && ( -
- -
- )} +
); };