Newsroom Planner uses other plugins functionality to complete some of it's tasks.
For example NRP underling on Naviga Photos to handle searching for images and handle images metadata.
NRP uses Dashboard portals to render other plugins components in it's own context.
Thanks to Dashboard mappings 🤓 you can replace Naviga Photos with your own image engine portal
and integrate your plugin into NRP
What kind of portals that NRP uses?
NRP uses 4 deferent portals in order to search for images and link them or display images as a gallery or upload images.
ImageSearch portal
This portal used to search for images, and link the selected images to the active Assignment.
Where is it rendered?:
In My Assignment view:
In Assignment Detail view:
Props:
NRP doesn't call any methods from ImageSearch portal
Example:
Copy const MySearchPortal = props => {
const [ selectedImages , setSelectedImages ] = useState ([])
const {
onLink
} = props
const handleOnSelect = selectedImage => {
const images = selectedImages .push (selectedImage)
setSelectedImages (images)
}
const handleLinkImages = () => {
/*
selectedImages format:
[
{
filename: 'myImage.jpg'
uuid: '123-123-321321-123-123'
},
{
filename: 'logo.jpg'
uuid: '444-423-774238-321-006'
}
]
*/
onLink (selectedImages)
}
return (
< div >
< SearchInput />
< LinkButton onClick = {handleLinkImages}/>
< ImagesWrapper onSelect = {handleOnSelect}>
< img />
< img />
< img />
< img />
< img />
</ ImagesWrapper >
</ div >
)
}
localizations:
Supports English & Swedish
Copy console .log ( this . props .localizations)
/*
{
link: 'Link selected photos'
}
*/
How NRP render ImageSearch:
Copy const ImageSearchWrapper = props => {
const {
editMode ,
localize ,
linkImagesToAssignment
} = props
const handleOnLink = selectedImages => {
linkImagesToAssignment (selectedImages)
}
return (
< div >
< ImageSearch
editMode = {editMode}
onLink = {handlOnLink}
localizations = {{
link : localize ( 'linkSelectedPhotos' )
}}
/>
</ div >
)
}
ImageGallery portal
This portal used to display the active assignment's images
Where is it rendered?:
In My Assignment view:
In Assignment Detail view:
Props:
NRP require some methods to be accessible from NRP components more info below
Example:
Copy const MyGalleryPortal = (props , ref) => {
const [ images , setImages ] = useState ( props .images)
const {
onSave ,
onCancel ,
onSelection
} = props
useEffect (() => {
/*
Methods will be called by NRP.
*/
if (ref && ref .current) {
ref .current = {
selectAll : () => {} ,
desselectAll : () => {} ,
updateImages : () => {}
}
}
})
const handleOnSelect = selectedImage => {
const mappedItems = images .map (item => {
if ( item .uuid === selectedImage .uuid) {
return {
... item ,
selected : true
}
} else {
return item
}
})
setImages (mappedItems)
// Update NRP with updated images
onSelection (mappedItems)
}
return (
< div >
< SearchInput />
< LinkButton onClick = {handleLinkImages}/>
< ImagesWrapper onSelect = {handleOnSelect}>
< img />
< img />
< img />
< img />
< img />
</ ImagesWrapper >
</ div >
)
}
export default forwardRef (MyGalleryPortal)
localizations:
Supports English & Swedish
Copy console .log ( this . props .localizations)
/*
{
link: 'Link selected photos'
}
*/
Functions should be accessible from NRP provided by ImageGallery portal:
updateImages
A function will give the updated images from the Assignment.
selectAll
A function to handle selecting all images.
desselectAll
A function to handle deselect all images.
How NRP render ImageGallery:
My Assignment view Assignment Detail view
Copy const MyAssignmentPortalWrapper = props => {
const {
assignment ,
confirm ,
closeConfirm ,
closeGallery ,
resetImageGalleryPortal
} = props
const imageGalleryRef = useRef ()
/*
This hook will track the active Assignemnt
if the user clicked on another assignment to show the images
this hook will call "updateImages" function from ImageGallery
portal and pass the new active Assignment's images
*/
useEffect (() => {
if ( imageGalleryRef .current && typeof imageGalleryRef . current .updateImages === 'function' ) {
const updatedImages = assignment . images .map (item => {
return {
uuid : item .uuid ,
filename : item .filename
}
})
imageGalleryRef . current .updateImages (updatedImages)
}
} , [ assignment .uuid])
const handleReset = () => {
resetImageGalleryPortal ()
}
const handleOnClose = () => {
if ( imageGalleryRef .current) {
if ( typeof imageGalleryRef . current .cancel === 'function' ) {
imageGalleryRef . current .cancel ()
}
}
closeGallery ()
}
const images = assignment . images .map (item => {
return {
uuid : item .uuid ,
filename : item .filename
}
})
return (
< div >
< CloseButton onClick = {handleOnClose}/>
< ImageGallery
editMode = { true }
managePhotos = { true }
confirm = {confirm}
images = { assignment .images}
ref = {imageGalleryRef}
onSave = {handleReset}
onCancel = {handleReset}
closeConfirm = {closeConfirm}
key = {imageGalleryRenderKey}
/>
</ div >
)
}
Copy const AssignmentDetailPortalWrapper = props => {
const {
assignment ,
confirm ,
closeConfirm ,
openMetadataModal
} = props
const [ selectedImages , setSelectedImages ] = useState ([])
const imageGalleryRef = useRef ()
const handleOnSelectction = images => {
setSelectedImages ( images .filter (image => image .selected))
}
const handleUnlinkFromAssignment = () => {
if ( selectedImages . length ) {
selectedImages .forEach (item => {
unlinkImage ( item .uuid)
})
if ( imageGalleryRef .current) {
if ( typeof imageGalleryRef . current .updateImages === 'function' ) {
const updatedImages = assignment . images .map (i => {
return {
uuid : i .uuid ,
filename : i .filename
}
})
imageGalleryRef . current .updateImages (updatedImages)
}
}
setSelectedImages ([])
}
}
const handleSelect = () => {
if ( imageGalleryRef .current) {
if ( ! selectedImages . length ) {
if ( typeof imageGalleryRef . current .selectAll === 'function' ) {
imageGalleryRef . current .selectAll ()
}
} else {
if ( typeof imageGalleryRef . current .desselectAll === 'function' ) {
imageGalleryRef . current .desselectAll ()
}
}
}
}
const handleImagesMetadata = () => {
/*
This function will open ImageMetadata portal inside a Modal
with all selected images
*/
openMetadataModal ({
images : selectedImages
})
}
const images = assignment . images .map (item => {
return {
uuid : item .uuid ,
filename : item .filename
}
})
return (
< div >
< OpenImagesMetadata onClick = {handleImagesMetadata}/>
< UnLinkButton onClick = {handleUnlinkFromAssignment}/>
< SelectButton onClick = {handleSelect}/>
< ImageGallery
editMode = { true }
fullWidth = { true }
confirm = {confirm}
images = {images}
ref = {imageGalleryRef}
closeConfirm = {closeConfirm}
onSelectction = {handleOnSelectction}
localizations = {{
link : localize ( 'linkSelectedPhotos' ) // 'Link selected photos'
}}
/>
</ div >
)
}
ImageUpload portal
This portal used to upload images, and provide the uploaded images to be linked to the active assignment.
Where is it rendered?:
In My Assignment view:
Props:
NRP require some methods to be accessible from NRP components more info below
Example:
Copy const MyUploadPortal = (props , ref) => {
const [ selectedFile , setSelectedFile ] = useState ( null )
const {
onDone ,
onUpload ,
onCancel
} = props
useEffect (() => {
/*
Methods will be called by NRP.
*/
if (ref && ref .current) {
ref .current = {
cancel : cancelProccess
}
}
})
const handlePhotos = file => {
setSelectedFile (file)
}
const handleUpload = () => {
if (selectedFile) {
onUpload ()
fetch ( 'api/upload' , {selectedFile})
.then ((response) => {
const uploadedImages = response . images .map (item => {
return {
uuid : item .uuid ,
filename : item .filename
}
})
onDone (uploadedImages)
})
}
}
const handleCancel = () => {
cancelProccess ()
onCancel ()
}
const cancelProcesses = () => {
// cacnel on going processes...
}
return (
< div >
< BrowsButton onChange = {handlePhotos}/>
< UploadButton onClick = {handleUpload}/>
< CancelButton onClick = {handleCancel}/>
</ div >
)
}
export default forwardRef (MyUploadPortal)
Functions should be accessible from NRP provided by ImageUpload portal:
cancel
A function will be called when the ImageUpload portal is unmounted to clean up onGoing processes for example.
How NRP render ImageUpload:
Copy const MyAssignmentPortalWrapper = props => {
const {
assignment ,
confirm ,
closeConfirm ,
closeUploadPortal
} = props
const imageUploadRef = useRef ()
const handleOnClose = () => {
if ( imageUploadRef .current) {
if ( typeof imageUploadRef . current .cancel === 'function' ) {
imageUploadRef . current .cancel ()
}
}
closeUploadPortal ()
}
const handleUploadedImages = uploadedImages => {
assignment .linkImages (uploadedImages)
}
const handleOnUploadStart = () => {
assignment .setUploadingFlag ()
}
return (
< div >
< CloseButton onClick = {handleOnClose}/>
< ImageUpload
confirm = {confirm}
ref = {imageUploadRef}
onCancel = {handleOnCancel}
closeConfirm = {closeConfirm}
onDone = {handleUploadedImages}
onUpload = {handleOnUploadStart}
/>
</ div >
)
}
ImageMetadata portal
This portal used to change images metadata
Where is it rendered?:
In Assignment Detail view:
Props:
NRP require some methods to be accessible from NRP components more info below
Example:
Copy const MyMetadataPortal = (props , ref) => {
const {
images ,
onSave ,
onCancel
} = props
useEffect (() => {
/*
Methods will be called by NRP.
*/
if (ref && ref .current) {
ref .current = {
cancel : cancelProccess
}
}
})
const handleSave = () => {
// Update images metadata
onSave ()
}
const handleCancel = () => {
cancelProccess ()
onCancel ()
}
const cancelProcesses = () => {
// cacnel on going processes...
}
const selectedImages = images .map (image => {
return (
< div key = { image .uuid}>
< TakenByField />
...
< img />
</ div >
)
})
return (
< div >
< SaveButton onChange = {handleSave}/>
< CancelButton onClick = {handleCancel}/>
{ selectedImages }
</ div >
)
}
export default forwardRef (MyUploadPortal)
Functions should be accessible from NRP provided by ImageMetadata portal:
cancel
A function will be called when the ImageMetadata portal is unmounted to clean up onGoing processes for example.
How NRP render ImageMetadata:
Copy const MyAssignmentPortalWrapper = props => {
const {
selectedImages ,
confirm ,
closeConfirm ,
closeMetadataPortal
} = props
const imageMetadataRef = useRef ()
const handleOnClose = () => {
if ( imageMetadataRef .current) {
if ( typeof imageMetadataRef . current .cancel === 'function' ) {
imageMetadataRef . current .cancel ()
}
}
closeMetadataPortal ()
}
const handleOnSave = () => {
closeMetadataPortal ()
}
const handleOnCancel = () => {
closeMetadataPortal ()
}
return (
< div >
< CloseButton onClick = {closeMetadataPortal}/>
< ImageMetadata
images = {selectedImages}
confirm = {confirm}
onSave = {handleOnSave}
onCancel = {handleOnCancel}
ref = {imageMetadataRef}
closeConfirm = {closeConfirm}
/>
</ div >
)
}