diff --git a/package-lock.json b/package-lock.json index 21fde080e..04ebdb702 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2540,6 +2540,21 @@ "rc-util": "^5.16.0" } }, + "@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, "@reduxjs/toolkit": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.6.tgz", @@ -9963,6 +9978,16 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "requires": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -11776,6 +11801,11 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==" }, + "immutability-helper": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-3.1.1.tgz", + "integrity": "sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -16143,6 +16173,26 @@ } } }, + "react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "requires": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + } + }, + "react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "requires": { + "dnd-core": "^16.0.1" + } + }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", diff --git a/package.json b/package.json index 500f03cec..6559cc472 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "compressorjs": "^1.1.1", "env-cmd": "^10.1.0", "i18next": "^22.0.5", + "immutability-helper": "^3.1.1", "js-cookie": "^3.0.1", "localforage": "^1.10.0", "moment": "^2.29.4", @@ -20,6 +21,8 @@ "rc-year-calendar": "^1.0.2", "react": "^18.2.0", "react-colorful": "^5.6.1", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", "react-easy-crop": "^5.0.0", "react-i18next": "^12.0.0", diff --git a/src/components/Accordion/CalendarAccordion/CalendarAccordion.jsx b/src/components/Accordion/CalendarAccordion/CalendarAccordion.jsx index e9fc75bec..06be0f2d1 100644 --- a/src/components/Accordion/CalendarAccordion/CalendarAccordion.jsx +++ b/src/components/Accordion/CalendarAccordion/CalendarAccordion.jsx @@ -90,10 +90,24 @@ function CalendarAccordion(props) { .unwrap() .then((response) => { if (type == 'organizers') { - setOrganizersList(treeEntitiesOption(response, user, calendarContentLanguage, sourceOptions.CMS)); + setOrganizersList( + treeEntitiesOption( + response?.map((v) => ({ ...v, image: v?.image?.find((image) => image?.isMain) })), + user, + calendarContentLanguage, + sourceOptions.CMS, + ), + ); } if (type == 'people') { - setPeopleList(treeEntitiesOption(response, user, calendarContentLanguage, sourceOptions.CMS)); + setPeopleList( + treeEntitiesOption( + response?.map((v) => ({ ...v, image: v?.image?.find((image) => image?.isMain) })), + user, + calendarContentLanguage, + sourceOptions.CMS, + ), + ); } }) .catch((error) => console.log(error)); @@ -111,13 +125,27 @@ function CalendarAccordion(props) { useEffect(() => { if (initialEntities && currentCalendarData) { - setOrganizersList(treeEntitiesOption(initialEntities, user, calendarContentLanguage, sourceOptions.CMS)); + setOrganizersList( + treeEntitiesOption( + initialEntities?.map((v) => ({ ...v, image: v?.image?.find((image) => image?.isMain) })), + user, + calendarContentLanguage, + sourceOptions.CMS, + ), + ); } }, [initialEntityLoading, currentCalendarData]); useEffect(() => { if (initialPersonEntities && currentCalendarData) { - setPeopleList(treeEntitiesOption(initialPersonEntities, user, calendarContentLanguage, sourceOptions.CMS)); + setPeopleList( + treeEntitiesOption( + initialPersonEntities?.map((v) => ({ ...v, image: v?.image?.find((image) => image?.isMain) })), + user, + calendarContentLanguage, + sourceOptions.CMS, + ), + ); } }, [initialPersonEntityLoading, currentCalendarData]); @@ -170,7 +198,11 @@ function CalendarAccordion(props) { if (response?.data?.length > 0) setSelectedPeople( treeEntitiesOption( - response?.data?.map((v) => ({ ...v, type: entitiesClass.people })), + response?.data?.map((v) => ({ + ...v, + type: entitiesClass.people, + image: v?.image?.find((image) => image?.isMain), + })), user, calendarContentLanguage, sourceOptions.CMS, diff --git a/src/components/ImageCrop/MultipleImageCrop.jsx b/src/components/ImageCrop/MultipleImageCrop.jsx new file mode 100644 index 000000000..1f7ac3392 --- /dev/null +++ b/src/components/ImageCrop/MultipleImageCrop.jsx @@ -0,0 +1,297 @@ +import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import './imageCrop.css'; +import { Row, Col, Space, Radio, Button } from 'antd'; +import { MinusOutlined, PlusOutlined } from '@ant-design/icons'; +import Cropper from 'react-easy-crop'; +import CustomModal from '../Modal/Common/CustomModal'; +import PrimaryButton from '../Button/Primary/Primary'; +import TextButton from '../Button/Text/Text'; +import { ratioChecker } from '../../utils/ratioChecker'; + +function MultipleImageCrop(props) { + const { image, open, setOpen, largeAspectRatio, thumbnailAspectRatio, form, fileList, setFileList, selectedUID } = + props; + let { cropValues } = props; + const { t } = useTranslation(); + + const ASPECT_RATIO_TYPE = { + large: { + value: largeAspectRatio ? ratioChecker(largeAspectRatio) : 16 / 9, + type: 'LARGE', + initial: + cropValues?.large?.height !== undefined && + cropValues?.large?.width !== undefined && + cropValues?.large?.x !== undefined && + cropValues?.large?.y !== undefined + ? cropValues?.large + : undefined, + }, + thumbnail: { + value: thumbnailAspectRatio ? ratioChecker(thumbnailAspectRatio) : 3 / 2, + type: 'THUMBNAIL', + initial: + cropValues?.thumbnail?.height !== undefined && + cropValues?.thumbnail?.width !== undefined && + cropValues?.thumbnail?.x !== undefined && + cropValues?.thumbnail?.y !== undefined + ? cropValues?.thumbnail + : undefined, + }, + }; + + const [largeCrop, onLargeCropChange] = useState({ x: 0, y: 0 }); + const [thumbnailCrop, onThumbnailCropChange] = useState({ x: 0, y: 0 }); + + const [largeZoom, onLargeZoomChange] = useState(1); + const [thumbnailZoom, onThumbnailZoomChange] = useState(1); + + const [aspectRatioType, setAspectRatioType] = useState(ASPECT_RATIO_TYPE.large.type); + const [initialLargeCroppedArea, setInitialLargeCroppedArea] = useState(undefined); + const [initialThumbnailCroppedArea, setInitialThumbnailCroppedArea] = useState(undefined); + + const onCropAreaChange = (croppedArea, croppedAreaPixel) => { + if ( + !isNaN(croppedAreaPixel?.x) && + !isNaN(croppedAreaPixel?.y) && + !isNaN(croppedAreaPixel?.height) && + !isNaN(croppedAreaPixel?.width) + ) { + switch (aspectRatioType) { + case ASPECT_RATIO_TYPE.large.type: + cropValues = { + ...cropValues, + large: { + x: croppedAreaPixel?.x, + y: croppedAreaPixel?.y, + height: croppedAreaPixel?.height, + width: croppedAreaPixel?.width, + }, + }; + + setInitialLargeCroppedArea(croppedAreaPixel); + break; + case ASPECT_RATIO_TYPE.thumbnail.type: + cropValues = { + ...cropValues, + thumbnail: { + x: croppedAreaPixel?.x, + y: croppedAreaPixel?.y, + height: croppedAreaPixel?.height, + width: croppedAreaPixel?.width, + }, + }; + + setInitialThumbnailCroppedArea(croppedAreaPixel); + break; + default: + break; + } + } + }; + + const aspectRatioControl = (type) => { + switch (type) { + case ASPECT_RATIO_TYPE.large.type: + setAspectRatioType(ASPECT_RATIO_TYPE.large.type); + break; + case ASPECT_RATIO_TYPE.thumbnail.type: + setAspectRatioType(ASPECT_RATIO_TYPE.thumbnail.type); + break; + default: + break; + } + }; + + const saveCropHandler = () => { + const newFileList = fileList?.map((file) => { + if (file.uid === selectedUID) { + return { + ...file, + cropValues: cropValues, + }; + } else return file; + }); + + setFileList(newFileList); + form.setFieldsValue({ + multipleImagesCrop: newFileList, + }); + setInitialLargeCroppedArea(cropValues?.large); + setInitialThumbnailCroppedArea(cropValues?.thumbnail); + setOpen(false); + }; + + const onCancel = () => { + setInitialLargeCroppedArea(undefined); + setInitialThumbnailCroppedArea(undefined); + setAspectRatioType(ASPECT_RATIO_TYPE.large.type); + onLargeCropChange({ x: 0, y: 0 }); + onThumbnailCropChange({ x: 0, y: 0 }); + setOpen(false); + }; + + useEffect(() => { + setInitialLargeCroppedArea(ASPECT_RATIO_TYPE.large.initial ?? undefined); + setInitialThumbnailCroppedArea(ASPECT_RATIO_TYPE.thumbnail.initial ?? undefined); + }, []); + + return ( + setOpen(false)} + title={ + + {t('dashboard.events.addEditEvent.otherInformation.image.crop.title')} + + } + footer={[ + onCancel()} + data-cy="button-image-crop-cancel" + />, + saveCropHandler()} + data-cy="button-image-crop-save" + />, + ]}> +
+ + + + {t('dashboard.events.addEditEvent.otherInformation.image.crop.subHeading')} + + + + aspectRatioControl(event.target.value)} + style={{ color: '#222732' }}> + + + {largeAspectRatio} {t('dashboard.events.addEditEvent.otherInformation.image.crop.largeImage')} + + + {thumbnailAspectRatio} {t('dashboard.events.addEditEvent.otherInformation.image.crop.thumbnailImage')} + + + + + + {aspectRatioType === ASPECT_RATIO_TYPE.large.type && ( +
+
+ )} + {aspectRatioType === ASPECT_RATIO_TYPE.thumbnail.type && ( +
+
+ )} + + +
+ {aspectRatioType === ASPECT_RATIO_TYPE.large.type && ( + + )} + {aspectRatioType === ASPECT_RATIO_TYPE.thumbnail.type && ( + + )} +
+ +
+
+
+ ); +} + +export default MultipleImageCrop; diff --git a/src/components/ImageCrop/index.js b/src/components/ImageCrop/index.js index 31882daf3..dabfccfda 100644 --- a/src/components/ImageCrop/index.js +++ b/src/components/ImageCrop/index.js @@ -1 +1,2 @@ -export { default } from './ImageCrop'; +export { default as ImageCrop } from './ImageCrop'; +export { default as MultipleImageCrop } from './MultipleImageCrop'; diff --git a/src/components/ImageUpload/ImageUpload.jsx b/src/components/ImageUpload/ImageUpload.jsx index 9e7f87d24..a45eece02 100644 --- a/src/components/ImageUpload/ImageUpload.jsx +++ b/src/components/ImageUpload/ImageUpload.jsx @@ -4,7 +4,7 @@ import { message, Upload, Form } from 'antd'; import { LoadingOutlined, DownloadOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'; import Outlined from '../Button/Outlined'; import { useTranslation } from 'react-i18next'; -import ImageCrop from '../ImageCrop'; +import { ImageCrop } from '../ImageCrop'; import { useOutletContext } from 'react-router-dom'; import { getWidthFromAspectRatio } from '../../utils/getWidthFromAspectRatio'; diff --git a/src/components/List/Events/List.jsx b/src/components/List/Events/List.jsx index 5d1604f54..95103322c 100644 --- a/src/components/List/Events/List.jsx +++ b/src/components/List/Events/List.jsx @@ -176,7 +176,7 @@ function Lists(props) { )} image?.isMain)?.thumbnail?.uri} className="event-list-image" style={{ border: diff --git a/src/components/Modal/QuickCreatePerson/QuickCreatePerson.jsx b/src/components/Modal/QuickCreatePerson/QuickCreatePerson.jsx index 7d2ab98c6..51194cc95 100644 --- a/src/components/Modal/QuickCreatePerson/QuickCreatePerson.jsx +++ b/src/components/Modal/QuickCreatePerson/QuickCreatePerson.jsx @@ -112,7 +112,7 @@ function QuickCreatePerson(props) { id: response?.id, name: response?.name, type: entitiesClass.person, - image: response?.image, + image: response?.image?.find((image) => image?.isMain), }, ]; createdPerson = treeEntitiesOption(createdPerson, user, calendarContentLanguage, sourceOptions.CMS); diff --git a/src/components/MultipleImageUpload/MultipleImageUpload.jsx b/src/components/MultipleImageUpload/MultipleImageUpload.jsx new file mode 100644 index 000000000..7be958dfc --- /dev/null +++ b/src/components/MultipleImageUpload/MultipleImageUpload.jsx @@ -0,0 +1,233 @@ +import { DownloadOutlined, DeleteOutlined } from '@ant-design/icons'; +import { Tooltip, Upload, message } from 'antd'; +import update from 'immutability-helper'; +import React, { useCallback, useRef, useState } from 'react'; +import { DndProvider, useDrag, useDrop } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; +import { useTranslation } from 'react-i18next'; +import Outlined from '../Button/Outlined'; +const type = 'DragableUploadList'; +import './multipleImageUpload.css'; + +const DragableUploadListItem = ({ originNode, moveRow, file, fileList }) => { + const ref = useRef(null); + + const index = fileList.indexOf(file); + const [{ isOver, dropClassName }, drop] = useDrop({ + accept: type, + collect: (monitor) => { + const { index: dragIndex } = monitor.getItem() || {}; + if (dragIndex === index) { + return {}; + } + return { + isOver: monitor.isOver(), + dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward', + }; + }, + drop: (item) => { + moveRow(item.index, index); + }, + }); + const [, drag] = useDrag({ + type, + item: { + index, + }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + drop(drag(ref)); + const errorNode = {originNode.props.children}; + return ( +
+ {file.status === 'error' ? errorNode : originNode} +
+ ); +}; + +const getBase64 = (img, callback) => { + const reader = new FileReader(); + reader.addEventListener('load', () => callback(reader.result)); + reader.readAsDataURL(img); + reader.addEventListener('load', (event) => { + const _loadedImageUrl = event.target.result; + const image = document.createElement('img'); + image.src = _loadedImageUrl; + }); +}; +const MultipleImageUpload = (props) => { + const { eventImageData, form, imageReadOnly } = props; + const { t } = useTranslation(); + + const [fileList, setFileList] = useState( + eventImageData?.length > 0 + ? eventImageData?.map((image) => { + return { + uid: image?.original?.entityId, + name: image?.original?.entityId, + status: 'done', + url: image?.original?.uri, + cropValues: { + large: { + x: image?.large?.xCoordinate ?? undefined, + y: image?.large?.yCoordinate ?? undefined, + height: image?.large?.height ?? undefined, + width: image?.large?.width ?? undefined, + }, + original: { + entityId: image?.original?.entityId ?? null, + height: image?.original?.height ?? undefined, + width: image?.original?.width ?? undefined, + }, + thumbnail: { + x: image?.thumbnail?.xCoordinate ?? undefined, + y: image?.thumbnail?.yCoordinate ?? undefined, + height: image?.thumbnail?.height ?? undefined, + width: image?.thumbnail?.width ?? undefined, + }, + }, + }; + }) + : [], + ); + + const moveRow = useCallback( + (dragIndex, hoverIndex) => { + const dragRow = fileList[dragIndex]; + let newFileList = update(fileList, { + $splice: [ + [dragIndex, 1], + [hoverIndex, 0, dragRow], + ], + }); + setFileList(newFileList); + form.setFieldsValue({ + multipleImagesCrop: newFileList, + }); + }, + [fileList], + ); + const onChange = ({ fileList: newFileList }) => { + let fileList = newFileList; + newFileList?.forEach((_, index) => { + if (newFileList[index].originFileObj) { + getBase64(newFileList[index].originFileObj, (url) => { + fileList[index].url = url; + if (!fileList[index].cropValues) + fileList[index].cropValues = { + large: { + x: undefined, + y: undefined, + height: undefined, + width: undefined, + }, + original: { + entityId: null, + height: undefined, + width: undefined, + }, + thumbnail: { + x: undefined, + y: undefined, + height: undefined, + width: undefined, + }, + }; + fileList[index].status = 'done'; + }); + } + }); + setFileList(fileList); + form.setFieldsValue({ + multipleImagesCrop: newFileList, + }); + }; + + const beforeUpload = (file) => { + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; + if (!isJpgOrPng) { + message.error(t('dashboard.events.addEditEvent.otherInformation.image.subHeading')); + } + return isJpgOrPng; + }; + + const customRequest = ({ onSuccess }) => { + setTimeout(() => { + onSuccess('ok'); + }, 0); + }; + return ( +
+ + , + }} + multiple + itemRender={(originNode, file, currFileList, actions) => + !imageReadOnly ? ( + + ) : ( + + + + + {file?.name} + + + + + + + + + ) + }> + {!imageReadOnly && ( +
+ + + + + {t('dashboard.events.addEditEvent.otherInformation.image.dragAndDrop')} + + +
+ )} +
+
+
+ ); +}; +export default MultipleImageUpload; diff --git a/src/components/MultipleImageUpload/index.js b/src/components/MultipleImageUpload/index.js new file mode 100644 index 000000000..d38b0b786 --- /dev/null +++ b/src/components/MultipleImageUpload/index.js @@ -0,0 +1,2 @@ +export { default } from './MultipleImageUpload.jsx'; +// Compare this snippet from src/components/MultipleImageUpload/index.js: diff --git a/src/components/MultipleImageUpload/multipleImageUpload.css b/src/components/MultipleImageUpload/multipleImageUpload.css new file mode 100644 index 000000000..5672ddd9a --- /dev/null +++ b/src/components/MultipleImageUpload/multipleImageUpload.css @@ -0,0 +1,73 @@ +.multiple-image-upload .ant-upload-select { + background: #ffffff !important; + border: 1px dashed #b6c1c9 !important; + height: 80px; + display: flex; + align-items: center; +} + +.multiple-image-upload-wrapper .image-footer { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + gap: 10px; + border: 1px solid #d9d9d9; + border-radius: 2px; + height: 66px; + padding: 8px; + margin-top: 8px; +} +.multiple-image-upload-wrapper .image-footer .image-contents, +.multiple-image-upload-wrapper .image-footer .image-actions { + display: flex; + align-items: center; + gap: 8px; +} + +.multiple-image-upload-wrapper .image-footer .image-actions { + cursor: pointer; +} +.multiple-image-upload-wrapper .image-footer .image-name { + white-space: nowrap; + cursor: pointer; +} +.multiple-image-upload-wrapper .image-footer .image-thumbnail { + display: block; + height: 48px; + min-height: 48px; + overflow: hidden; + /* width: 48px; */ +} + +.multiple-image-upload-wrapper .image-footer .edit-image { + border: 1px solid #607efc; + border-radius: 2px; + padding: 2px 4px; +} + +.multiple-image-upload-wrapper .multiple-image-upload .upload-helper-text { + color: #646d7b; + font-weight: 400; + font-size: 16px; +} + +@media (max-width: 480px) { + .multiple-image-upload-wrapper .image-footer .image-name { + text-wrap: wrap; + font-size: 12px; + } + + .multiple-image-upload-wrapper .image-footer .image-actions .span-remove-image > span, + .multiple-image-upload-wrapper .image-footer .image-actions .span-edit-image > span { + font-size: 12px; + } + + .multiple-image-upload-wrapper .multiple-image-upload .upload-helper-text { + font-size: 12px; + } + + .multiple-image-upload-wrapper .multiple-image-upload .ant-upload { + padding: 8px 0 !important; + } +} diff --git a/src/constants/calendarSettingsForm.js b/src/constants/calendarSettingsForm.js index 8fa4cfaf9..5df5dcf44 100644 --- a/src/constants/calendarSettingsForm.js +++ b/src/constants/calendarSettingsForm.js @@ -267,38 +267,36 @@ export const calendarSettingsFormFields = { }, { name: '', - label: ( - {(t) => t('dashboard.settings.calendarSettings.imageAspectRatio.imageAspectRatio')} - ), - field: ({ - t, - aspectRatios, - // customRatio, setCustomRatio, setAspectRatioOptions - }) => { - //Custom aspect ratio has been removed as per https://github.com/culturecreates/footlight-app/issues/635#issuecomment-2073409623 - - // const addItem = (e, type) => { - // e.preventDefault(); - // if (aspectRatios.find((item) => item.value === customRatio[type])) return; - // else - // setAspectRatioOptions([ - // ...aspectRatios, - // { label: customRatio[type], value: customRatio[type], title: customRatio[type] }, - // ]); - // setCustomRatio({ - // large: '', - // thumbnail: '', - // }); - // }; + label: '', + field: ({ t, aspectRatios }) => { return ( + +

+ {(t) => t('dashboard.settings.calendarSettings.siteImageSettings.title')} +

+ + +

+ + {(t) => t('dashboard.settings.calendarSettings.siteImageSettings.description')} + +

+ + + + + {(t) => t('dashboard.settings.calendarSettings.siteImageSettings.thumbnailSettings')} + + + + data-cy="form-item-image-ratio-thumbnail"> } clearIcon={} treeData={aspectRatios} - // dropdownRender={(menu) => ( - // <> - // {menu} - // - // - // - // setCustomRatio({ - // ...customRatio, - // large: e.target.value, - // }) - // } - // /> - // - // - // - // )} data-cy="treeselect-calendar-image-aspect-ratio" tagRender={(props) => { const { closable, onClose, label } = props; @@ -347,10 +325,38 @@ export const calendarSettingsFormFields = { + + + +
+ ); + }, + rules: [], + hidden: false, + required: true, + }, + { + name: '', + label: ( + {(t) => t('dashboard.settings.calendarSettings.siteImageSettings.largeSettings')} + ), + field: ({ t, aspectRatios }) => { + return ( + + + } clearIcon={} treeData={aspectRatios} - // dropdownRender={(menu) => ( - // <> - // {menu} - // - // - // - // setCustomRatio({ - // ...customRatio, - // thumbnail: e.target.value, - // }) - // } - // /> - // - // - // - // )} data-cy="treeselect-calendar-filter-events" tagRender={(props) => { const { closable, onClose, label } = props; @@ -398,24 +384,15 @@ export const calendarSettingsFormFields = { /> - - ); - }, - rules: [], - hidden: false, - required: true, - }, - { - name: '', - label: {(t) => t('dashboard.settings.calendarSettings.imageMaxWidth.imageMaxWidth')}, - field: ({ t }) => { - return ( - {(t) => t('dashboard.settings.calendarSettings.imageMaxWidth.large')}} + label={ + + {(t) => t('dashboard.settings.calendarSettings.siteImageSettings.maximumWidth')} + + } data-cy="form-item-image-max-width-large" rules={[REQUIRED_MESSAGE]}> - - - - + + + + + + + + + + {t('dashboard.settings.calendarSettings.siteImageSettings.addImageGallery')} + + + ); diff --git a/src/constants/formFields.js b/src/constants/formFields.js index 1a5832ddc..f2fa180c7 100644 --- a/src/constants/formFields.js +++ b/src/constants/formFields.js @@ -19,6 +19,7 @@ import BilingualTextEditor from '../components/BilingualTextEditor'; import Outlined from '../components/Button/Outlined'; import { sourceOptions } from './sourceOptions'; import LoadingIndicator from '../components/LoadingIndicator'; +import MultipleImageUpload from '../components/MultipleImageUpload'; const { TextArea } = Input; @@ -366,6 +367,9 @@ export const formFieldValue = [ imageCropOpen, largeAspectRatio, thumbnailAspectRatio, + eventImageGalleryData, + enableGallery, + t, }) => ( <> {position === 'top' && datatype === dataTypes.IMAGE &&

{userTips}

} @@ -383,6 +387,20 @@ export const formFieldValue = [ thumbnailAspectRatio={thumbnailAspectRatio} formName={name} /> + {name?.includes(mappedFieldTypes.IMAGE) && ( + + )} ), }, @@ -704,11 +722,11 @@ export const returnFormDataWithFields = ({ }), largeUrl: field?.mappedField === mappedFieldTypes.IMAGE - ? entityData?.image?.large?.uri + ? entityData?.image?.find((image) => image?.isMain)?.large?.uri : field?.mappedField === mappedFieldTypes.LOGO && entityData?.logo?.large?.uri, originalUrl: field?.mappedField === mappedFieldTypes.IMAGE - ? entityData?.image?.original?.uri + ? entityData?.image?.find((image) => image?.isMain)?.original?.uri : field?.mappedField === mappedFieldTypes.LOGO && entityData?.logo?.original?.uri, required: checkMandatoryAdminOnlyFields(field?.name, mandatoryFields), t: t, @@ -722,9 +740,10 @@ export const returnFormDataWithFields = ({ isCrop: isCrop, setImageCropOpen, imageCropOpen, + eventImageGalleryData: entityData?.image?.filter((image) => !image?.isMain), eventImageData: field?.mappedField === mappedFieldTypes.IMAGE - ? entityData?.image + ? entityData?.image?.find((image) => image?.isMain) : field?.mappedField === mappedFieldTypes.LOGO && entityData?.logo, largeAspectRatio: currentCalendarData?.imageConfig?.length > 0 ? currentCalendarData?.imageConfig[0]?.large?.aspectRatio : null, @@ -732,6 +751,8 @@ export const returnFormDataWithFields = ({ currentCalendarData?.imageConfig?.length > 0 ? currentCalendarData?.imageConfig[0]?.thumbnail?.aspectRatio : null, + enableGallery: + currentCalendarData?.imageConfig?.length > 0 ? currentCalendarData?.imageConfig[0]?.enableGallery : false, placesSearch, allPlacesList, allPlacesArtsdataList, diff --git a/src/locales/en/translationEn.json b/src/locales/en/translationEn.json index 50542e460..0e8ad0f1c 100644 --- a/src/locales/en/translationEn.json +++ b/src/locales/en/translationEn.json @@ -252,9 +252,12 @@ }, "image": { "title": "Image", - "subHeading": " Images should be landscape or square and at least 600px wide. Only JPEG and PNG files are supported.", + "mainImage": "Main image", + "additionalImages": "Additional images", + "subHeading": "Only JPEG and PNG files are supported.", "dragAndDrop": "or drag and drop to upload", "browse": "Browse", + "imageGallery": "Image Gallery", "crop": { "title": "Position image", "subHeading": "Adjust position if necessary.", @@ -697,6 +700,8 @@ }, "image": { "image": "Image", + "mainImage": "Main image", + "additionalImages": "Additional images", "subheading": "Only .jpeg and .png files are accepted." }, "addMoreDetails": "Add more details", @@ -1004,6 +1009,15 @@ "thumbnail": "Thumbnail image", "large": "Large image" }, + "siteImageSettings": { + "title": "Site image settings", + "description": "Customize image settings for your website.", + "thumbnailSettings": "Thumbnail settings", + "largeSettings": "Large settings", + "aspectRatio": "Aspect ratio", + "maximumWidth": "Maximum width", + "addImageGallery": "Add image gallery" + }, "calendarLogo": "Calendar Logo", "calendarLogoDescription": "Only JPEG and PNG files are supported.", "calendarWidgetSetup": "Calendar widget setup", diff --git a/src/locales/fr/transalationFr.json b/src/locales/fr/transalationFr.json index c3da4e5f7..b3460447b 100644 --- a/src/locales/fr/transalationFr.json +++ b/src/locales/fr/transalationFr.json @@ -252,9 +252,12 @@ }, "image": { "title": "Image", + "mainImage": "Image principale", + "additionalImages": "Images supplémentaires", "subHeading": "Les images doivent être au format paysage ou carré et mesurer au moins 600 px de large. Uniquement les fichiers .jpeg et .png sont acceptés.", "dragAndDrop": "ou glisser pour télécharger", "browse": "Parcourir", + "imageGallery": "Galerie d'images", "crop": { "title": "Positionnement de l’image", "subHeading": "Ajuster la position de l’image si nécessaire.", @@ -693,6 +696,8 @@ }, "image": { "image": "Image", + "mainImage": "Image principale", + "additionalImages": "Images supplémentaires", "subheading": "Uniquement les fichiers .jpeg et .png sont acceptés." }, "addMoreDetails": "Ajouter plus de détails", @@ -998,6 +1003,15 @@ "thumbnail": "Vignette", "large": "Grande image" }, + "siteImageSettings": { + "title": "Paramètres de l'image du site", + "description": "Personnalisez les paramètres de l'image pour votre site web.", + "thumbnailSettings": "Paramètres des vignettes", + "largeSettings": "Grands paramètres", + "aspectRatio": "Format d'image", + "maximumWidth": "Largeur maximale", + "addImageGallery": "Ajouter la galerie d'images" + }, "calendarLogo": "Logo du calendrier", "calendarLogoDescription": "Uniquement les fichiers .jpeg et .png sont acceptés.", "calendarWidgetSetup": "Configuration du widget calendrier", diff --git a/src/pages/Dashboard/AddEvent/AddEvent.jsx b/src/pages/Dashboard/AddEvent/AddEvent.jsx index a0864a699..00f747b7a 100644 --- a/src/pages/Dashboard/AddEvent/AddEvent.jsx +++ b/src/pages/Dashboard/AddEvent/AddEvent.jsx @@ -104,6 +104,7 @@ import { } from '../../../redux/reducer/languageLiteralSlice'; import { removeUneditedFallbackValues } from '../../../utils/removeUneditedFallbackValues'; import { groupEventsByDate } from '../../../utils/groupSubEventsConfigByDate'; +import MultipleImageUpload from '../../../components/MultipleImageUpload'; import { adminCheckHandler } from '../../../utils/adminCheckHandler'; import { getCurrentCalendarDetailsFromUserDetails } from '../../../utils/getCurrentCalendarDetailsFromUserDetails'; @@ -227,6 +228,9 @@ function AddEvent() { }), ); + let imageConfig = currentCalendarData?.imageConfig?.length > 0 && currentCalendarData?.imageConfig[0]; + let mainImageData = eventData?.image?.find((image) => image?.isMain) || null; + const calendarContentLanguage = currentCalendarData?.contentLanguage; const dateTimeConverter = (date, time) => { let dateSelected = date.format('DD-MM-YYYY'); @@ -347,7 +351,7 @@ function AddEvent() { : []), ]), ]) - .then(() => { + .then(async () => { let fallbackStatus = activeFallbackFieldsInfo; if (clear) { dispatch(setLanguageLiteralBannerDisplayStatus(false)); @@ -729,25 +733,77 @@ function AddEvent() { subEventConfiguration: eventData?.subEventConfiguration, }; - let imageCrop = form.getFieldValue('imageCrop'); - imageCrop = { - large: { - xCoordinate: imageCrop?.large?.x, - yCoordinate: imageCrop?.large?.y, - height: imageCrop?.large?.height, - width: imageCrop?.large?.width, - }, - thumbnail: { - xCoordinate: imageCrop?.thumbnail?.x, - yCoordinate: imageCrop?.thumbnail?.y, - height: imageCrop?.thumbnail?.height, - width: imageCrop?.thumbnail?.width, - }, - original: { - entityId: imageCrop?.original?.entityId, - height: imageCrop?.original?.height, - width: imageCrop?.original?.width, + let imageCrop = [form.getFieldValue('imageCrop')]; + imageCrop = [ + { + large: { + xCoordinate: imageCrop[0]?.large?.x, + yCoordinate: imageCrop[0]?.large?.y, + height: imageCrop[0]?.large?.height, + width: imageCrop[0]?.large?.width, + }, + thumbnail: { + xCoordinate: imageCrop[0]?.thumbnail?.x, + yCoordinate: imageCrop[0]?.thumbnail?.y, + height: imageCrop[0]?.thumbnail?.height, + width: imageCrop[0]?.thumbnail?.width, + }, + original: { + entityId: imageCrop[0]?.original?.entityId, + height: imageCrop[0]?.original?.height, + width: imageCrop[0]?.original?.width, + }, + isMain: true, }, + ]; + + const uploadImageList = async () => { + for (let i = 0; i < values.multipleImagesCrop.length; i++) { + const file = values.multipleImagesCrop[i]?.originFileObj; + if (!file) { + if (values.multipleImagesCrop[i]?.cropValues) + imageCrop.push(values.multipleImagesCrop[i]?.cropValues); + else imageCrop.push(values.multipleImagesCrop[i]); + continue; + } + + const formdata = new FormData(); + formdata.append('file', file); + + try { + const response = await addImage({ data: formdata, calendarId }).unwrap(); + + // Process each image in the list + const { large, thumbnail } = values.multipleImagesCrop[i]?.cropValues || {}; + const { original, height, width } = response?.data || {}; + + const galleryImage = { + large: { + xCoordinate: large?.x, + yCoordinate: large?.y, + height: large?.height, + width: large?.width, + }, + original: { + entityId: original?.entityId ?? null, + height, + width, + }, + thumbnail: { + xCoordinate: thumbnail?.x, + yCoordinate: thumbnail?.y, + height: thumbnail?.height, + width: thumbnail?.width, + }, + }; + + // Add the processed image to imageCrop + imageCrop.push(galleryImage); + } catch (error) { + console.log(error); + throw error; // rethrow to stop further execution + } + } }; if (values?.dragger?.length > 0 && values?.dragger[0]?.originFileObj) { @@ -756,32 +812,42 @@ function AddEvent() { formdata && addImage({ data: formdata, calendarId }) .unwrap() - .then((response) => { + .then(async (response) => { if (featureFlags.imageCropFeature) { let entityId = response?.data?.original?.entityId; - imageCrop = { - ...imageCrop, - original: { - entityId, - height: response?.data?.height, - width: response?.data?.width, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; } else - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId: response?.data?.original?.entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; + + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); eventObj['image'] = imageCrop; addUpdateEventApiHandler(eventObj, toggle) .then((id) => resolve(id)) .catch((error) => { reject(error); + console.log(error); }); }) @@ -791,8 +857,10 @@ function AddEvent() { element && element[0]?.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } else { + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); if (values?.draggerWrap) { - if (values?.dragger && values?.dragger?.length == 0) eventObj['image'] = null; + if (values?.dragger && values?.dragger?.length == 0 && values.multipleImagesCrop?.length == 0) + eventObj['image'] = null; else eventObj['image'] = imageCrop; } @@ -1474,7 +1542,7 @@ function AddEvent() { name: organizer?.entity?.name, type: organizer?.type, logo: organizer?.entity?.logo, - image: organizer?.entity?.image, + image: organizer?.entity?.image?.find((image) => image?.isMain), contactPoint: organizer?.entity?.contactPoint, creator: organizer?.entity?.creator, }; @@ -1497,7 +1565,7 @@ function AddEvent() { name: performer?.entity?.name, type: performer?.type, logo: performer?.entity?.logo, - image: performer?.entity?.image, + image: performer?.entity?.image?.find((image) => image?.isMain), creator: performer?.entity?.creator, }; }); @@ -1520,7 +1588,7 @@ function AddEvent() { name: supporter?.entity?.name, type: supporter?.type, logo: supporter?.entity?.logo, - image: supporter?.entity?.image, + image: supporter?.entity?.image?.find((image) => image?.isMain), creator: supporter?.entity?.creator, }; }); @@ -1640,28 +1708,59 @@ function AddEvent() { }; setFormValue(obj); } - if (eventData?.image) { - form.setFieldsValue({ - imageCrop: { + if (eventData?.image?.length > 0) { + const mainImage = eventData.image.find((image) => image?.isMain) || null; + const imageGalleryImages = eventData.image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ large: { - x: eventData?.image?.large?.xCoordinate, - y: eventData?.image?.large?.yCoordinate, - height: eventData?.image?.large?.height, - width: eventData?.image?.large?.width, + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, }, original: { - entityId: eventData?.image?.original?.entityId ?? null, - height: eventData?.image?.original?.height, - width: eventData?.image?.original?.width, + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, }, thumbnail: { - x: eventData?.image?.thumbnail?.xCoordinate, - y: eventData?.image?.thumbnail?.yCoordinate, - height: eventData?.image?.thumbnail?.height, - width: eventData?.image?.thumbnail?.width, + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, }, - }, - }); + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } } } else { navigate(`${PathName.Dashboard}/${calendarId}${PathName.Events}/${eventId}`, { @@ -3438,7 +3537,7 @@ function AddEvent() { 0) || - (eventData?.image?.original?.uri && !getFieldValue('dragger')) || - (eventData?.image?.original?.uri && getFieldValue('dragger')?.length > 0) + (mainImageData?.original?.uri && !getFieldValue('dragger')) || + (mainImageData?.original?.uri && getFieldValue('dragger')?.length > 0) ) { return Promise.resolve(); } else @@ -3478,14 +3577,14 @@ function AddEvent() { 0 ? currentCalendarData?.imageConfig[0]?.large?.aspectRatio @@ -3499,6 +3598,26 @@ function AddEvent() { isCrop={featureFlags.imageCropFeature} /> + { + .then(async () => { var values = form.getFieldsValue(true); let organizationPayload = {}; Object.keys(values)?.map((object) => { @@ -322,25 +322,76 @@ function CreateNewOrganization() { }, }; } - let imageCrop = form.getFieldValue('imageCrop'); - imageCrop = { - large: { - xCoordinate: imageCrop?.large?.x, - yCoordinate: imageCrop?.large?.y, - height: imageCrop?.large?.height, - width: imageCrop?.large?.width, - }, - thumbnail: { - xCoordinate: imageCrop?.thumbnail?.x, - yCoordinate: imageCrop?.thumbnail?.y, - height: imageCrop?.thumbnail?.height, - width: imageCrop?.thumbnail?.width, - }, - original: { - entityId: imageCrop?.original?.entityId, - height: imageCrop?.original?.height, - width: imageCrop?.original?.width, + let imageCrop = [form.getFieldValue('imageCrop')]; + imageCrop = [ + { + large: { + xCoordinate: imageCrop[0]?.large?.x, + yCoordinate: imageCrop[0]?.large?.y, + height: imageCrop[0]?.large?.height, + width: imageCrop[0]?.large?.width, + }, + thumbnail: { + xCoordinate: imageCrop[0]?.thumbnail?.x, + yCoordinate: imageCrop[0]?.thumbnail?.y, + height: imageCrop[0]?.thumbnail?.height, + width: imageCrop[0]?.thumbnail?.width, + }, + original: { + entityId: imageCrop[0]?.original?.entityId, + height: imageCrop[0]?.original?.height, + width: imageCrop[0]?.original?.width, + }, + isMain: true, }, + ]; + + const uploadImageList = async () => { + for (let i = 0; i < values?.multipleImagesCrop.length; i++) { + const file = values.multipleImagesCrop[i]?.originFileObj; + if (!file) { + if (values.multipleImagesCrop[i]?.cropValues) imageCrop.push(values.multipleImagesCrop[i]?.cropValues); + else imageCrop.push(values.multipleImagesCrop[i]); + continue; + } + + const formdata = new FormData(); + formdata.append('file', file); + + try { + const response = await addImage({ data: formdata, calendarId }).unwrap(); + + // Process each image in the list + const { large, thumbnail } = values.multipleImagesCrop[i]?.cropValues || {}; + const { original, height, width } = response?.data || {}; + + const galleryImage = { + large: { + xCoordinate: large?.x, + yCoordinate: large?.y, + height: large?.height, + width: large?.width, + }, + original: { + entityId: original?.entityId ?? null, + height, + width, + }, + thumbnail: { + xCoordinate: thumbnail?.x, + yCoordinate: thumbnail?.y, + height: thumbnail?.height, + width: thumbnail?.width, + }, + }; + + // Add the processed image to imageCrop + imageCrop.push(galleryImage); + } catch (error) { + console.log(error); + throw error; // rethrow to stop further execution + } + } }; if ((values?.image || (values?.image && values?.image?.length > 0)) && !values?.logo) { if (values?.image?.length > 0 && values?.image[0]?.originFileObj) { @@ -349,27 +400,36 @@ function CreateNewOrganization() { formdata && addImage({ data: formdata, calendarId }) .unwrap() - .then((response) => { + .then(async (response) => { if (featureFlags.imageCropFeature) { - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + let entityId = response?.data?.original?.entityId; + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; } else - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId: response?.data?.original?.entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; + + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); organizationPayload['image'] = imageCrop; addUpdateOrganizationApiHandler(organizationPayload, toggle) .then((id) => resolve(id)) @@ -384,8 +444,10 @@ function CreateNewOrganization() { element && element[0]?.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } else { + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); if (values?.image) { - if (values?.image && values?.image?.length == 0) organizationPayload['image'] = null; + if (values?.image && values?.image?.length == 0 && values.multipleImagesCrop?.length == 0) + organizationPayload['image'] = null; else organizationPayload['image'] = imageCrop; } addUpdateOrganizationApiHandler(organizationPayload, toggle) @@ -402,7 +464,7 @@ function CreateNewOrganization() { formdata && addImage({ data: formdata, calendarId }) .unwrap() - .then((response) => { + .then(async (response) => { organizationPayload['logo'] = { original: { entityId: response?.data?.original?.entityId, @@ -412,6 +474,8 @@ function CreateNewOrganization() { large: {}, thumbnail: {}, }; + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); + organizationPayload['image'] = imageCrop; addUpdateOrganizationApiHandler(organizationPayload, toggle); }) .catch((error) => { @@ -420,6 +484,10 @@ function CreateNewOrganization() { element && element[0]?.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } else { + if (values.multipleImagesCrop?.length > 0) { + await uploadImageList(); + organizationPayload['image'] = imageCrop; + } if (values?.logo) { if (values?.logo && values?.logo?.length == 0) organizationPayload['logo'] = null; else organizationPayload['logo'] = organizationData?.logo; @@ -441,27 +509,36 @@ function CreateNewOrganization() { formdata && addImage({ data: formdata, calendarId }) .unwrap() - .then((response) => { + .then(async (response) => { if (featureFlags.imageCropFeature) { - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + let entityId = response?.data?.original?.entityId; + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; } else - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId: response?.data?.original?.entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; + + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); organizationPayload['image'] = imageCrop; if (values?.logo?.length > 0 && values?.logo[0]?.originFileObj) { const formdata = new FormData(); @@ -510,8 +587,13 @@ function CreateNewOrganization() { element && element[0]?.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } else { + if (values.multipleImagesCrop?.length > 0) { + await uploadImageList(); + organizationPayload['image'] = imageCrop; + } if (values?.image) { - if (values?.image && values?.image?.length == 0) organizationPayload['image'] = null; + if (values?.image && values?.image?.length == 0 && values.multipleImagesCrop?.length == 0) + organizationPayload['image'] = null; else organizationPayload['image'] = imageCrop; } if (values?.logo?.length > 0 && values?.logo[0]?.originFileObj) { @@ -560,8 +642,13 @@ function CreateNewOrganization() { if (values?.logo && values?.logo?.length == 0) organizationPayload['logo'] = null; else organizationPayload['logo'] = organizationData?.logo; } + if (values.multipleImagesCrop?.length > 0) { + await uploadImageList(); + organizationPayload['image'] = imageCrop; + } if (values?.image) { - if (values?.image && values?.image?.length == 0) organizationPayload['image'] = null; + if (values?.image && values?.image?.length == 0 && values.multipleImagesCrop?.length > 0) + organizationPayload['image'] = null; else organizationPayload['image'] = imageCrop; } addUpdateOrganizationApiHandler(organizationPayload, toggle) @@ -713,28 +800,59 @@ function CreateNewOrganization() { initialPlace; if (organizationData) { if (routinghandler(user, calendarId, organizationData?.createdByUserId, null, true, organizationData?.id)) { - if (organizationData?.image) { - form.setFieldsValue({ - imageCrop: { + if (organizationData?.image?.length > 0) { + const mainImage = organizationData.image.find((image) => image?.isMain) || null; + const imageGalleryImages = organizationData.image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ large: { - x: organizationData?.image?.large?.xCoordinate, - y: organizationData?.image?.large?.yCoordinate, - height: organizationData?.image?.large?.height, - width: organizationData?.image?.large?.width, + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, }, original: { - entityId: organizationData?.image?.original?.entityId ?? null, - height: organizationData?.image?.original?.height, - width: organizationData?.image?.original?.width, + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, }, thumbnail: { - x: organizationData?.image?.thumbnail?.xCoordinate, - y: organizationData?.image?.thumbnail?.yCoordinate, - height: organizationData?.image?.thumbnail?.height, - width: organizationData?.image?.thumbnail?.width, + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, }, - }, - }); + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } } if (organizationData?.sameAs?.length > 0) { let sourceId = artsDataLinkChecker(organizationData?.sameAs); @@ -799,28 +917,59 @@ function CreateNewOrganization() { ); } if (externalCalendarEntityData?.length > 0 && externalCalendarEntityId) { - if (externalCalendarEntityData[0]?.image) { - form.setFieldsValue({ - imageCrop: { + if (externalCalendarEntityData[0]?.image?.length > 0) { + const mainImage = externalCalendarEntityData[0].image.find((image) => image?.isMain) || null; + const imageGalleryImages = externalCalendarEntityData[0].image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ large: { - x: externalCalendarEntityData[0]?.image?.large?.xCoordinate, - y: externalCalendarEntityData[0]?.image?.large?.yCoordinate, - height: externalCalendarEntityData[0]?.image?.large?.height, - width: externalCalendarEntityData[0]?.image?.large?.width, + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, }, original: { - entityId: externalCalendarEntityData[0]?.image?.original?.entityId ?? null, - height: externalCalendarEntityData[0]?.image?.original?.height, - width: externalCalendarEntityData[0]?.image?.original?.width, + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, }, thumbnail: { - x: externalCalendarEntityData[0]?.image?.thumbnail?.xCoordinate, - y: externalCalendarEntityData[0]?.image?.thumbnail?.yCoordinate, - height: externalCalendarEntityData[0]?.image?.thumbnail?.height, - width: externalCalendarEntityData[0]?.image?.thumbnail?.width, + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, }, - }, - }); + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } } if (externalCalendarEntityData[0]?.derivedFrom?.uri) { let sourceId = getExternalSourceId(externalCalendarEntityData[0]?.derivedFrom?.uri); diff --git a/src/pages/Dashboard/CreateNewPerson/CreateNewPerson.jsx b/src/pages/Dashboard/CreateNewPerson/CreateNewPerson.jsx index 70c6aaa85..7a5ca107b 100644 --- a/src/pages/Dashboard/CreateNewPerson/CreateNewPerson.jsx +++ b/src/pages/Dashboard/CreateNewPerson/CreateNewPerson.jsx @@ -242,7 +242,7 @@ function CreateNewPerson() { form .validateFields(validateFieldList) - .then(() => { + .then(async () => { var values = form.getFieldsValue(true); let personPayload = {}; Object.keys(values)?.map((object) => { @@ -255,25 +255,76 @@ function CreateNewPerson() { }; } }); - let imageCrop = form.getFieldValue('imageCrop'); - imageCrop = { - large: { - xCoordinate: imageCrop?.large?.x, - yCoordinate: imageCrop?.large?.y, - height: imageCrop?.large?.height, - width: imageCrop?.large?.width, - }, - thumbnail: { - xCoordinate: imageCrop?.thumbnail?.x, - yCoordinate: imageCrop?.thumbnail?.y, - height: imageCrop?.thumbnail?.height, - width: imageCrop?.thumbnail?.width, - }, - original: { - entityId: imageCrop?.original?.entityId, - height: imageCrop?.original?.height, - width: imageCrop?.original?.width, + let imageCrop = [form.getFieldValue('imageCrop')]; + imageCrop = [ + { + large: { + xCoordinate: imageCrop[0]?.large?.x, + yCoordinate: imageCrop[0]?.large?.y, + height: imageCrop[0]?.large?.height, + width: imageCrop[0]?.large?.width, + }, + thumbnail: { + xCoordinate: imageCrop[0]?.thumbnail?.x, + yCoordinate: imageCrop[0]?.thumbnail?.y, + height: imageCrop[0]?.thumbnail?.height, + width: imageCrop[0]?.thumbnail?.width, + }, + original: { + entityId: imageCrop[0]?.original?.entityId, + height: imageCrop[0]?.original?.height, + width: imageCrop[0]?.original?.width, + }, + isMain: true, }, + ]; + + const uploadImageList = async () => { + for (let i = 0; i < values.multipleImagesCrop.length; i++) { + const file = values.multipleImagesCrop[i]?.originFileObj; + if (!file) { + if (values.multipleImagesCrop[i]?.cropValues) imageCrop.push(values.multipleImagesCrop[i]?.cropValues); + else imageCrop.push(values.multipleImagesCrop[i]); + continue; + } + + const formdata = new FormData(); + formdata.append('file', file); + + try { + const response = await addImage({ data: formdata, calendarId }).unwrap(); + + // Process each image in the list + const { large, thumbnail } = values.multipleImagesCrop[i]?.cropValues || {}; + const { original, height, width } = response?.data || {}; + + const galleryImage = { + large: { + xCoordinate: large?.x, + yCoordinate: large?.y, + height: large?.height, + width: large?.width, + }, + original: { + entityId: original?.entityId ?? null, + height, + width, + }, + thumbnail: { + xCoordinate: thumbnail?.x, + yCoordinate: thumbnail?.y, + height: thumbnail?.height, + width: thumbnail?.width, + }, + }; + + // Add the processed image to imageCrop + imageCrop.push(galleryImage); + } catch (error) { + console.log(error); + throw error; // rethrow to stop further execution + } + } }; if (values?.image?.length > 0 && values?.image[0]?.originFileObj) { const formdata = new FormData(); @@ -281,27 +332,36 @@ function CreateNewPerson() { formdata && addImage({ data: formdata, calendarId }) .unwrap() - .then((response) => { + .then(async (response) => { if (featureFlags.imageCropFeature) { - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + let entityId = response?.data?.original?.entityId; + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; } else - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId: response?.data?.original?.entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; + + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); personPayload['image'] = imageCrop; addUpdatePersonApiHandler(personPayload); }) @@ -311,10 +371,11 @@ function CreateNewPerson() { element && element[0]?.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } else { + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); if (values?.image) { - if (values?.image && values?.image?.length == 0) personPayload['image'] = null; - else personPayload['image'] = imageCrop; - } else if (values?.imageCrop) personPayload['image'] = imageCrop; + if (values?.image && values?.image?.length == 0 && values.multipleImagesCrop?.length == 0) + personPayload['image'] = null; + } else personPayload['image'] = imageCrop; addUpdatePersonApiHandler(personPayload); } }) @@ -385,28 +446,59 @@ function CreateNewPerson() { if (calendarId && currentCalendarData) { if (personData) { if (routinghandler(user, calendarId, personData?.createdByUserId, null, true, personData?.id)) { - if (personData?.image) { - form.setFieldsValue({ - imageCrop: { + if (personData?.image?.length > 0) { + const mainImage = personData.image.find((image) => image?.isMain) || null; + const imageGalleryImages = personData.image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ large: { - x: personData?.image?.large?.xCoordinate, - y: personData?.image?.large?.yCoordinate, - height: personData?.image?.large?.height, - width: personData?.image?.large?.width, + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, }, original: { - entityId: personData?.image?.original?.entityId ?? null, - height: personData?.image?.original?.height, - width: personData?.image?.original?.width, + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, }, thumbnail: { - x: personData?.image?.thumbnail?.xCoordinate, - y: personData?.image?.thumbnail?.yCoordinate, - height: personData?.image?.thumbnail?.height, - width: personData?.image?.thumbnail?.width, + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, }, - }, - }); + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } } if (personData?.sameAs?.length > 0) { let sourceId = artsDataLinkChecker(personData?.sameAs); @@ -419,27 +511,60 @@ function CreateNewPerson() { ); } if (externalCalendarEntityData?.length > 0 && externalCalendarEntityId) { - form.setFieldsValue({ - imageCrop: { - large: { - x: externalCalendarEntityData[0]?.image?.large?.xCoordinate, - y: externalCalendarEntityData[0]?.image?.large?.yCoordinate, - height: externalCalendarEntityData[0]?.image?.large?.height, - width: externalCalendarEntityData[0]?.image?.large?.width, - }, - original: { - entityId: externalCalendarEntityData[0]?.image?.original?.entityId ?? null, - height: externalCalendarEntityData[0]?.image?.original?.height, - width: externalCalendarEntityData[0]?.image?.original?.width, - }, - thumbnail: { - x: externalCalendarEntityData[0]?.image?.thumbnail?.xCoordinate, - y: externalCalendarEntityData[0]?.image?.thumbnail?.yCoordinate, - height: externalCalendarEntityData[0]?.image?.thumbnail?.height, - width: externalCalendarEntityData[0]?.image?.thumbnail?.width, - }, - }, - }); + if (externalCalendarEntityData[0]?.image?.length > 0) { + const mainImage = externalCalendarEntityData[0].image.find((image) => image?.isMain) || null; + const imageGalleryImages = externalCalendarEntityData[0].image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ + large: { + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, + }, + original: { + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, + }, + thumbnail: { + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, + }, + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } + } if (externalCalendarEntityData[0]?.sameAs?.length > 0) { let sourceId = artsDataLinkChecker(externalCalendarEntityData[0]?.sameAs); sourceId = getExternalSourceId(sourceId); diff --git a/src/pages/Dashboard/CreateNewPlace/CreateNewPlace.jsx b/src/pages/Dashboard/CreateNewPlace/CreateNewPlace.jsx index 35871a76e..719393f5e 100644 --- a/src/pages/Dashboard/CreateNewPlace/CreateNewPlace.jsx +++ b/src/pages/Dashboard/CreateNewPlace/CreateNewPlace.jsx @@ -89,6 +89,7 @@ import { setLanguageLiteralBannerDisplayStatus, } from '../../../redux/reducer/languageLiteralSlice'; import Alert from '../../../components/Alert'; +import MultipleImageUpload from '../../../components/MultipleImageUpload'; import { adminCheckHandler } from '../../../utils/adminCheckHandler'; import { getCurrentCalendarDetailsFromUserDetails } from '../../../utils/getCurrentCalendarDetailsFromUserDetails'; @@ -172,6 +173,7 @@ function CreateNewPlace() { return { fieldName: field }; }), ); + let imageConfig = currentCalendarData?.imageConfig?.length > 0 && currentCalendarData?.imageConfig[0]; const { currentData: placeData, isLoading: isPlaceLoading } = useGetPlaceQuery( { placeId: placeId, calendarId, sessionId: timestampRef }, @@ -246,6 +248,7 @@ function CreateNewPlace() { additionalType: [], accessibility: [], }; + let mainImageData = placeData?.image?.find((image) => image?.isMain) || null; const calendar = getCurrentCalendarDetailsFromUserDetails(user, calendarId); @@ -428,7 +431,7 @@ function CreateNewPlace() { var promise = new Promise(function (resolve, reject) { form .validateFields(publishValidateFields ?? []) - .then(() => { + .then(async () => { var values = form.getFieldsValue(true); let placeObj, languageKey, @@ -472,26 +475,29 @@ function CreateNewPlace() { }; }); } - let imageCrop = form.getFieldValue('imageCrop'); - imageCrop = { - large: { - xCoordinate: imageCrop?.large?.x, - yCoordinate: imageCrop?.large?.y, - height: imageCrop?.large?.height, - width: imageCrop?.large?.width, - }, - thumbnail: { - xCoordinate: imageCrop?.thumbnail?.x, - yCoordinate: imageCrop?.thumbnail?.y, - height: imageCrop?.thumbnail?.height, - width: imageCrop?.thumbnail?.width, - }, - original: { - entityId: imageCrop?.original?.entityId, - height: imageCrop?.original?.height, - width: imageCrop?.original?.width, + let imageCrop = [form.getFieldValue('imageCrop')]; + imageCrop = [ + { + large: { + xCoordinate: imageCrop[0]?.large?.x, + yCoordinate: imageCrop[0]?.large?.y, + height: imageCrop[0]?.large?.height, + width: imageCrop[0]?.large?.width, + }, + thumbnail: { + xCoordinate: imageCrop[0]?.thumbnail?.x, + yCoordinate: imageCrop[0]?.thumbnail?.y, + height: imageCrop[0]?.thumbnail?.height, + width: imageCrop[0]?.thumbnail?.width, + }, + original: { + entityId: imageCrop[0]?.original?.entityId, + height: imageCrop[0]?.original?.height, + width: imageCrop[0]?.original?.width, + }, + isMain: true, }, - }; + ]; if (values?.containedInPlace || values?.containedInPlace?.length > 0) { if (containedInPlace?.source === sourceOptions.CMS) containedInPlaceObj = { @@ -576,33 +582,89 @@ function CreateNewPlace() { ...(values?.dynamicFields && { dynamicFields }), ...(values?.containsPlace && { containsPlace }), }; + const uploadImageList = async () => { + for (let i = 0; i < values.multipleImagesCrop.length; i++) { + const file = values.multipleImagesCrop[i]?.originFileObj; + if (!file) { + if (values.multipleImagesCrop[i]?.cropValues) imageCrop.push(values.multipleImagesCrop[i]?.cropValues); + else imageCrop.push(values.multipleImagesCrop[i]); + continue; + } + + const formdata = new FormData(); + formdata.append('file', file); + + try { + const response = await addImage({ data: formdata, calendarId }).unwrap(); + + // Process each image in the list + const { large, thumbnail } = values.multipleImagesCrop[i]?.cropValues || {}; + const { original, height, width } = response?.data || {}; + + const galleryImage = { + large: { + xCoordinate: large?.x, + yCoordinate: large?.y, + height: large?.height, + width: large?.width, + }, + original: { + entityId: original?.entityId ?? null, + height, + width, + }, + thumbnail: { + xCoordinate: thumbnail?.x, + yCoordinate: thumbnail?.y, + height: thumbnail?.height, + width: thumbnail?.width, + }, + }; + // Add the processed image to imageCrop + imageCrop.push(galleryImage); + } catch (error) { + console.log(error); + throw error; // rethrow to stop further execution + } + } + }; if (values?.dragger?.length > 0 && values?.dragger[0]?.originFileObj) { const formdata = new FormData(); formdata.append('file', values?.dragger[0].originFileObj); formdata && addImage({ data: formdata, calendarId }) .unwrap() - .then((response) => { + .then(async (response) => { if (featureFlags.imageCropFeature) { let entityId = response?.data?.original?.entityId; - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; } else - imageCrop = { - ...imageCrop, - original: { - ...imageCrop?.original, - entityId: response?.data?.original?.entityId, - height: response?.data?.height, - width: response?.data?.width, + imageCrop = [ + { + large: imageCrop[0]?.large, + thumbnail: imageCrop[0]?.thumbnail, + isMain: true, + original: { + entityId: response?.data?.original?.entityId, + height: response?.data?.height, + width: response?.data?.width, + }, }, - }; + ]; + + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); placeObj['image'] = imageCrop; addUpdatePlaceApiHandler(placeObj, postalObj) .then((id) => resolve(id)) @@ -617,8 +679,10 @@ function CreateNewPlace() { element && element[0]?.scrollIntoView({ block: 'center', behavior: 'smooth' }); }); } else { + if (values.multipleImagesCrop?.length > 0) await uploadImageList(); if (values?.draggerWrap) { - if (values?.dragger && values?.dragger?.length == 0) placeObj['image'] = null; + if (values?.dragger && values?.dragger?.length == 0 && values.multipleImagesCrop?.length == 0) + placeObj['image'] = null; else placeObj['image'] = imageCrop; } @@ -886,28 +950,59 @@ function CreateNewPlace() { .catch((error) => console.log(error)); form.setFieldValue(formFieldNames.CONTAINED_IN_PLACE, placeData?.containedInPlace?.entityId); } - if (placeData?.image) { - form.setFieldsValue({ - imageCrop: { + if (placeData?.image?.length > 0) { + const mainImage = placeData.image.find((image) => image?.isMain) || null; + const imageGalleryImages = placeData.image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ large: { - x: placeData?.image?.large?.xCoordinate, - y: placeData?.image?.large?.yCoordinate, - height: placeData?.image?.large?.height, - width: placeData?.image?.large?.width, + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, }, original: { - entityId: placeData?.image?.original?.entityId ?? null, - height: placeData?.image?.original?.height, - width: placeData?.image?.original?.width, + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, }, thumbnail: { - x: placeData?.image?.thumbnail?.xCoordinate, - y: placeData?.image?.thumbnail?.yCoordinate, - height: placeData?.image?.thumbnail?.height, - width: placeData?.image?.thumbnail?.width, + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, }, - }, - }); + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } } if (placeData?.containsPlace?.length > 0) { let initialContainsPlace = placeData?.containsPlace?.map((place) => { @@ -944,28 +1039,59 @@ function CreateNewPlace() { getArtsDataPlace(sourceId); } - if (externalCalendarEntityData[0]?.image) { - form.setFieldsValue({ - imageCrop: { + if (externalCalendarEntityData[0]?.image?.length > 0) { + const mainImage = externalCalendarEntityData[0].image.find((image) => image?.isMain) || null; + const imageGalleryImages = externalCalendarEntityData[0].image.filter((image) => !image?.isMain); + + if (mainImage) { + form.setFieldsValue({ + imageCrop: { + large: { + x: mainImage?.large?.xCoordinate, + y: mainImage?.large?.yCoordinate, + height: mainImage?.large?.height, + width: mainImage?.large?.width, + }, + original: { + entityId: mainImage?.original?.entityId ?? null, + height: mainImage?.original?.height, + width: mainImage?.original?.width, + }, + thumbnail: { + x: mainImage?.thumbnail?.xCoordinate, + y: mainImage?.thumbnail?.yCoordinate, + height: mainImage?.thumbnail?.height, + width: mainImage?.thumbnail?.width, + }, + }, + }); + } + + if (imageGalleryImages.length > 0) { + const galleryImages = imageGalleryImages.map((image) => ({ large: { - x: externalCalendarEntityData[0]?.image?.large?.xCoordinate, - y: externalCalendarEntityData[0]?.image?.large?.yCoordinate, - height: externalCalendarEntityData[0]?.image?.large?.height, - width: externalCalendarEntityData[0]?.image?.large?.width, + x: image?.large?.xCoordinate, + y: image?.large?.yCoordinate, + height: image?.large?.height, + width: image?.large?.width, }, original: { - entityId: externalCalendarEntityData[0]?.image?.original?.entityId ?? null, - height: externalCalendarEntityData[0]?.image?.original?.height, - width: externalCalendarEntityData[0]?.image?.original?.width, + entityId: image?.original?.entityId ?? null, + height: image?.original?.height, + width: image?.original?.width, }, thumbnail: { - x: externalCalendarEntityData[0]?.image?.thumbnail?.xCoordinate, - y: externalCalendarEntityData[0]?.image?.thumbnail?.yCoordinate, - height: externalCalendarEntityData[0]?.image?.thumbnail?.height, - width: externalCalendarEntityData[0]?.image?.thumbnail?.width, + x: image?.thumbnail?.xCoordinate, + y: image?.thumbnail?.yCoordinate, + height: image?.thumbnail?.height, + width: image?.thumbnail?.width, }, - }, - }); + })); + + form.setFieldsValue({ + multipleImagesCrop: galleryImages, + }); + } } if (externalCalendarEntityData[0]?.place?.entityId) { @@ -1665,12 +1791,12 @@ function CreateNewPlace() { 0 && externalCalendarEntityData[0].image && @@ -1688,8 +1814,8 @@ function CreateNewPlace() { if ( (getFieldValue(formFieldNames.DRAGGER) != undefined && getFieldValue(formFieldNames.DRAGGER)?.length > 0) || - (placeData?.image?.original?.uri && !getFieldValue(formFieldNames.DRAGGER)) || - (placeData?.image?.original?.uri && getFieldValue(formFieldNames.DRAGGER)?.length > 0) + (mainImageData?.original?.uri && !getFieldValue(formFieldNames.DRAGGER)) || + (mainImageData?.original?.uri && getFieldValue(formFieldNames.DRAGGER)?.length > 0) ) { return Promise.resolve(); } else @@ -1711,14 +1837,14 @@ function CreateNewPlace() { data-cy="image-upload-place" imageUrl={ placeId - ? placeData?.image?.large?.uri + ? mainImageData?.large?.uri : externalCalendarEntityId && externalCalendarEntityData?.length > 0 && externalCalendarEntityData[0]?.image?.large?.uri } originalImageUrl={ placeId - ? placeData?.image?.original?.uri + ? mainImageData?.original?.uri : externalCalendarEntityId && externalCalendarEntityData?.length > 0 && externalCalendarEntityData[0]?.image?.original?.uri @@ -1730,7 +1856,7 @@ function CreateNewPlace() { form={form} eventImageData={ placeId - ? placeData?.image + ? mainImageData : externalCalendarEntityId && externalCalendarEntityData?.length > 0 && externalCalendarEntityData[0]?.image @@ -1748,6 +1874,25 @@ function CreateNewPlace() { isCrop={featureFlags.imageCropFeature} /> + {allTaxonomyData?.data?.map((taxonomy, index) => { if (taxonomy?.isDynamicField) { let initialValues; diff --git a/src/pages/Dashboard/EventReadOnly/EventReadOnly.jsx b/src/pages/Dashboard/EventReadOnly/EventReadOnly.jsx index 0be460eb2..959080cb1 100644 --- a/src/pages/Dashboard/EventReadOnly/EventReadOnly.jsx +++ b/src/pages/Dashboard/EventReadOnly/EventReadOnly.jsx @@ -41,6 +41,7 @@ import ArtsDataInfo from '../../../components/ArtsDataInfo/ArtsDataInfo'; import { artsDataLinkChecker } from '../../../utils/artsDataLinkChecker'; import { getEmbedUrl } from '../../../utils/getEmbedVideoUrl'; import { sameAsTypes } from '../../../constants/sameAsTypes'; +import MultipleImageUpload from '../../../components/MultipleImageUpload'; import { adminCheckHandler } from '../../../utils/adminCheckHandler'; import { getCurrentCalendarDetailsFromUserDetails } from '../../../utils/getCurrentCalendarDetailsFromUserDetails'; @@ -93,6 +94,8 @@ function EventReadOnly() { let dynamicAdminOnlyFields = requiredFields?.adminOnlyFields?.dynamicFields; const calendarContentLanguage = currentCalendarData?.contentLanguage; let artsDataLink = eventData?.sameAs?.filter((item) => item?.type === sameAsTypes.ARTSDATA_IDENTIFIER); + const mainImageData = eventData?.image?.find((image) => image?.isMain) || null; + const imageConfig = currentCalendarData?.imageConfig?.length > 0 && currentCalendarData?.imageConfig[0]; useEffect(() => { if (eventData?.recurringEvent || eventData?.subEventConfiguration) setDateType(dateTypes.MULTIPLE); @@ -108,7 +111,7 @@ function EventReadOnly() { name: organizer?.entity?.name, type: organizer?.type, logo: organizer?.entity?.logo, - image: organizer?.entity?.image, + image: organizer?.entity?.image?.find((image) => image?.isMain), }; }); setSelectedOrganizers(treeEntitiesOption(initialOrganizers, user, calendarContentLanguage, sourceOptions.CMS)); @@ -121,7 +124,7 @@ function EventReadOnly() { name: performer?.entity?.name, type: performer?.type, logo: performer?.entity?.logo, - image: performer?.entity?.image, + image: performer?.entity?.image?.find((image) => image?.isMain), }; }); setSelectedPerformers(treeEntitiesOption(initialPerformers, user, calendarContentLanguage, sourceOptions.CMS)); @@ -134,7 +137,7 @@ function EventReadOnly() { name: supporter?.entity?.name, type: supporter?.type, logo: supporter?.entity?.logo, - image: supporter?.entity?.image, + image: supporter?.entity?.image?.find((image) => image?.isMain), }; }); setSelectedSupporters(treeEntitiesOption(initialSupporters, user, calendarContentLanguage, sourceOptions.CMS)); @@ -696,7 +699,7 @@ function EventReadOnly() { )}
- {eventData?.image && eventData?.image?.original?.uri && ( + {eventData?.image?.length > 0 && mainImageData?.original?.uri && (

- {t('dashboard.events.addEditEvent.otherInformation.image.title')} + {t('dashboard.events.addEditEvent.otherInformation.image.mainImage')}

+
+ )} + {eventData?.image?.length > 0 && imageConfig.enableGallery && ( +
+

+ {t('dashboard.events.addEditEvent.otherInformation.image.additionalImages')} +

+ 0 ? imageConfig?.large?.aspectRatio : null + } + thumbnailAspectRatio={ + currentCalendarData?.imageConfig?.length > 0 ? imageConfig?.thumbnail?.aspectRatio : null + } + eventImageData={eventData?.image?.filter((image) => !image?.isMain)} />
)} diff --git a/src/pages/Dashboard/OrganizationsReadOnly/OrganizationsReadOnly.jsx b/src/pages/Dashboard/OrganizationsReadOnly/OrganizationsReadOnly.jsx index 957f99aae..b57374239 100644 --- a/src/pages/Dashboard/OrganizationsReadOnly/OrganizationsReadOnly.jsx +++ b/src/pages/Dashboard/OrganizationsReadOnly/OrganizationsReadOnly.jsx @@ -29,6 +29,7 @@ import { getExternalSourceId } from '../../../utils/getExternalSourceId'; import { CalendarOutlined, UserOutlined, EnvironmentOutlined } from '@ant-design/icons'; import moment from 'moment'; import { useLazyGetEntityDependencyDetailsQuery } from '../../../services/entities'; +import MultipleImageUpload from '../../../components/MultipleImageUpload'; function OrganizationsReadOnly() { const { t } = useTranslation(); @@ -78,6 +79,7 @@ function OrganizationsReadOnly() { const [derivedEntitiesData, setDerivedEntitiesData] = useState(); const calendarContentLanguage = currentCalendarData?.contentLanguage; + const imageConfig = currentCalendarData?.imageConfig?.length > 0 && currentCalendarData?.imageConfig[0]; const getArtsData = (id) => { setArtsDataLoading(true); @@ -406,6 +408,23 @@ function OrganizationsReadOnly() { ))} )} + {organizationData?.image?.length > 0 && imageConfig.enableGallery && ( +
+

+ {t('dashboard.events.addEditEvent.otherInformation.image.additionalImages')} +

+ 0 ? imageConfig?.large?.aspectRatio : null + } + thumbnailAspectRatio={ + currentCalendarData?.imageConfig?.length > 0 ? imageConfig?.thumbnail?.aspectRatio : null + } + eventImageData={organizationData?.image?.filter((image) => !image?.isMain)} + /> +
+ )} {organizationData?.contactPoint && (

diff --git a/src/pages/Dashboard/People/People.jsx b/src/pages/Dashboard/People/People.jsx index fab445498..e737cb340 100644 --- a/src/pages/Dashboard/People/People.jsx +++ b/src/pages/Dashboard/People/People.jsx @@ -454,7 +454,7 @@ function People() { data-cy="list-item-person" key={index} id={index} - logo={item?.image?.thumbnail?.uri} + logo={item?.image?.find((image) => image?.isMain)?.thumbnail?.uri} defaultLogo={ } diff --git a/src/pages/Dashboard/PersonReadOnly/PersonReadOnly.jsx b/src/pages/Dashboard/PersonReadOnly/PersonReadOnly.jsx index 432ead8b2..9d4392e51 100644 --- a/src/pages/Dashboard/PersonReadOnly/PersonReadOnly.jsx +++ b/src/pages/Dashboard/PersonReadOnly/PersonReadOnly.jsx @@ -32,6 +32,7 @@ import Icon, { EnvironmentOutlined, CalendarOutlined } from '@ant-design/icons'; import moment from 'moment'; import SelectionItem from '../../../components/List/SelectionItem'; import { useLazyGetEntityDependencyDetailsQuery } from '../../../services/entities'; +import MultipleImageUpload from '../../../components/MultipleImageUpload'; function PersonReadOnly() { const { t } = useTranslation(); @@ -77,6 +78,9 @@ function PersonReadOnly() { const [derivedEntitiesData, setDerivedEntitiesData] = useState(); const [derivedEntitiesDisplayStatus, setDerivedEntitiesDisplayStatus] = useState(false); + const mainImageData = personData?.image?.find((image) => image?.isMain) || null; + const imageConfig = currentCalendarData?.imageConfig?.length > 0 && currentCalendarData?.imageConfig[0]; + const getArtsData = (id) => { setArtsDataLoading(true); loadArtsDataEntity({ entityId: id }) @@ -442,13 +446,30 @@ function PersonReadOnly() { ))} )} + {personData?.image?.length > 0 && imageConfig.enableGallery && ( + +

+ {t('dashboard.events.addEditEvent.otherInformation.image.additionalImages')} +

+ 0 ? imageConfig?.large?.aspectRatio : null + } + thumbnailAspectRatio={ + currentCalendarData?.imageConfig?.length > 0 ? imageConfig?.thumbnail?.aspectRatio : null + } + eventImageData={personData?.image?.filter((image) => !image?.isMain)} + /> + + )} - {personData?.image?.original?.uri && ( + {mainImageData?.original?.uri && (
avatar image?.isMain) || null; + const imageConfig = currentCalendarData?.imageConfig?.length > 0 && currentCalendarData?.imageConfig[0]; const getArtsDataPlace = (id) => { setArtsDataLoading(true); @@ -172,7 +175,7 @@ function PlaceReadOnly() { disambiguatingDescription: place?.disambiguatingDescription, id: place?.id, name: place?.name, - image: place?.image, + image: place?.image?.find((image) => image?.isMain), uri: artsDataLinkChecker(place?.sameAs), }; }); @@ -451,14 +454,33 @@ function PlaceReadOnly() { )} )} + {placeData?.image?.length > 0 && imageConfig.enableGallery && ( + +
+

+ {t('dashboard.events.addEditEvent.otherInformation.image.additionalImages')} +

+ 0 ? imageConfig?.large?.aspectRatio : null + } + thumbnailAspectRatio={ + currentCalendarData?.imageConfig?.length > 0 ? imageConfig?.thumbnail?.aspectRatio : null + } + eventImageData={placeData?.image?.filter((image) => !image?.isMain)} + /> +
+ + )} - {placeData?.image?.original?.uri && ( + {mainImageData?.original?.uri && (
avatar { @@ -83,7 +78,6 @@ function CalendarSettings() { const handleInitialFilters = (data, selectedFilters) => { return data?.filter((filter) => selectedFilters?.includes(filter.value))?.map((filter) => filter.value) ?? []; }; - // initialSelectedFilters = ['63a0a47c1c6b6c005aad30da', '6467a0a5137a2200640d6abd']; initialSelectedFilters = [ { @@ -104,10 +98,7 @@ function CalendarSettings() { }, ]; - const imageConfig = - currentCalendarData?.imageConfig?.length > 0 - ? currentCalendarData?.imageConfig?.filter((config) => config?.entityName == entitiesClass.event)[0] - : null; + const imageConfig = currentCalendarData?.imageConfig?.length > 0 ? currentCalendarData?.imageConfig[0] : null; let aspectRatioSet = new Set([ '1:1', '2:1', @@ -152,6 +143,7 @@ function CalendarSettings() { }, calendarLogo: currentCalendarData?.logo?.original?.uri, readOnly: currentCalendarData?.mode === calendarModes.READ_ONLY ? true : false, + enableGallery: imageConfig?.enableGallery, }; const udpateCalendarHandler = (data) => { @@ -224,7 +216,11 @@ function CalendarSettings() { dateFormatDisplay: values.calendarDateFormat, imageConfig: [ { - entityName: entitiesClass.event, + entityNames: Object.keys(entitiesClass) + .map((key) => { + if (entitiesClass[key] !== entitiesClass.people) return entitiesClass[key]; + }) + ?.filter((key) => key), large: { aspectRatio: values.imageAspectRatio.large, maxWidth: Number(values.imageMaxWidth.large), @@ -233,6 +229,7 @@ function CalendarSettings() { aspectRatio: values.imageAspectRatio.thumbnail, maxWidth: Number(values.imageMaxWidth.thumbnail), }, + enableGallery: values?.enableGallery ?? false, }, ], mode: values.readOnly ? calendarModes.READ_ONLY : calendarModes.READ_WRITE, diff --git a/src/pages/Dashboard/Settings/CalendarSettings/calendarSettings.css b/src/pages/Dashboard/Settings/CalendarSettings/calendarSettings.css index 8ac20c293..10d01a313 100644 --- a/src/pages/Dashboard/Settings/CalendarSettings/calendarSettings.css +++ b/src/pages/Dashboard/Settings/CalendarSettings/calendarSettings.css @@ -5,6 +5,29 @@ color: #222732; } +.calendar-settings-wrapper .calendar-settings-title { + font-size: 20px; + font-weight: 700; + line-height: 32px; + color: #222732; +} + +.calendar-settings-wrapper .calendar-thumbnail-settings-required::after { + display: inline-block; + margin-right: 4px; + color: #ff4d4f; + font-size: 14px; + font-family: SimSun, sans-serif; + line-height: 1; + content: '*'; +} + +.calendar-settings-wrapper .calendar-settings-label { + font-size: 16px; + font-weight: 700; + line-height: 32px; + color: #222732; +} .calendar-settings-wrapper .calendar-settings-description { font-size: 16px; font-weight: 400;