diff --git a/.gitignore b/.gitignore index 3d97dd0e..27a89505 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ tmp .env # dependencies node_modules +uploads # IDEs and editors /.idea diff --git a/apps/frontend/src/components/launches/add.edit.model.tsx b/apps/frontend/src/components/launches/add.edit.model.tsx index 38c434de..aad7c3b0 100644 --- a/apps/frontend/src/components/launches/add.edit.model.tsx +++ b/apps/frontend/src/components/launches/add.edit.model.tsx @@ -50,9 +50,13 @@ import { useUser } from '@gitroom/frontend/components/layout/user.context'; import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; import Image from 'next/image'; import { weightedLength } from '@gitroom/helpers/utils/count.length'; +import { useVariables } from '@gitroom/react/helpers/variable.context'; +import Uppy from '@uppy/core'; +import { getUppyUploadPlugin } from '@gitroom/react/helpers/uppy.upload'; import { uniqBy } from 'lodash'; import { Select } from '@gitroom/react/form/select'; + function countCharacters(text: string, type: string): number { if (type !== 'x') { return text.length; @@ -107,6 +111,7 @@ export const AddEditModal: FC<{ >([{ content: '' }]); const fetch = useFetch(); + const { backendUrl, storageProvider } = useVariables(); const user = useUser(); @@ -406,6 +411,42 @@ export const AddEditModal: FC<{ }); }, [data, postFor, selectedIntegrations]); + const uploadMediaToServer = (_file: File, index: number) => { + const uppy2 = new Uppy({ + autoProceed: true, + restrictions: { + maxNumberOfFiles: 1, + allowedFileTypes: ['image/*', 'video/mp4'], + maxFileSize: 1000000000, + }, + }); + + const { plugin, options } = getUppyUploadPlugin( + storageProvider, + fetch, + backendUrl + ); + uppy2.use(plugin, options); + uppy2.addFile(_file); + + uppy2.on('complete', (result) => { + if (result) { + const mediaToAdd = result?.successful![0].response?.body; + + if (mediaToAdd && mediaToAdd.path && mediaToAdd.id) { + const newMedia: { + path: string; + id: string; + }[] = [ + ...(value[index].image || []), + { path: mediaToAdd.path, id: mediaToAdd.id }, + ]; + changeImage(index)({ target: { name: 'image', value: newMedia } }); + } + } + }); + }; + return ( <> {user?.tier?.ai && ( @@ -529,6 +570,34 @@ export const AddEditModal: FC<{ preview="edit" // @ts-ignore onChange={changeValue(index)} + onPaste={(event) => { + const clipboardData = + event.clipboardData || + ( + window as Window & + typeof globalThis & { + clipboardData: DataTransfer; + } + ).clipboardData; + if (clipboardData && clipboardData.items) { + for (const item of Array.from( + clipboardData.items + )) { + const mediaTypes = ['image', 'video']; + + if ( + mediaTypes.some( + (type) => item.type.indexOf(type) !== -1 + ) + ) { + const media = item.getAsFile(); + if(media){ + uploadMediaToServer(media, index); + } + } + } + } + }} /> {showError && diff --git a/apps/frontend/src/components/launches/editor.tsx b/apps/frontend/src/components/launches/editor.tsx index e2906b01..07fbc801 100644 --- a/apps/frontend/src/components/launches/editor.tsx +++ b/apps/frontend/src/components/launches/editor.tsx @@ -54,6 +54,7 @@ export const Editor = forwardRef< textareaPurpose: `Assist me in writing social media posts.`, chatApiConfigs: {}, }} + onPaste={props.onPaste} /> ) : ( diff --git a/apps/frontend/src/components/media/media.component.tsx b/apps/frontend/src/components/media/media.component.tsx index d9393e58..1f826af0 100644 --- a/apps/frontend/src/components/media/media.component.tsx +++ b/apps/frontend/src/components/media/media.component.tsx @@ -215,25 +215,19 @@ export const MultiMediaComponent: FC<{ }> = (props) => { const { name, label, error, description, onChange, value } = props; const user = useUser(); - useEffect(() => { - if (value) { - setCurrentMedia(value); - } - }, []); const [modal, setShowModal] = useState(false); const [mediaModal, setMediaModal] = useState(false); - const [currentMedia, setCurrentMedia] = useState(value); const mediaDirectory = useMediaDirectory(); const changeMedia = useCallback( (m: { path: string; id: string }) => { - const newMedia = [...(currentMedia || []), m]; - setCurrentMedia(newMedia); + const newMedia = [...(value || []), m]; + // setCurrentMedia(newMedia); onChange({ target: { name, value: newMedia } }); }, - [currentMedia] + [value] ); const showModal = useCallback(() => { @@ -246,11 +240,11 @@ export const MultiMediaComponent: FC<{ const clearMedia = useCallback( (topIndex: number) => () => { - const newMedia = currentMedia?.filter((f, index) => index !== topIndex); - setCurrentMedia(newMedia); + const newMedia = value?.filter((f, index) => index !== topIndex); + // setCurrentMedia(newMedia); onChange({ target: { name, value: newMedia } }); }, - [currentMedia] + [value] ); const designMedia = useCallback(() => { @@ -310,8 +304,8 @@ export const MultiMediaComponent: FC<{ - {!!currentMedia && - currentMedia.map((media, index) => ( + {!!value && + value.map((media, index) => ( <>
{ @@ -86,7 +87,7 @@ export function MultipartFileUploaderAfter({ onUploadSuccess(result); }); - uppy2.on('upload-success', (file, response) => { + uppy2.on('upload-success', (file, response) => { // @ts-ignore uppy.setFileState(file.id, { // @ts-ignore