Skip to content

Commit

Permalink
* implement popover tool tips
Browse files Browse the repository at this point in the history
  • Loading branch information
CalamityC committed May 6, 2024
1 parent dc2f6c9 commit 5d2ee04
Show file tree
Hide file tree
Showing 12 changed files with 342 additions and 32 deletions.
9 changes: 9 additions & 0 deletions rdmo/projects/assets/js/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,12 @@ export const FETCH_FILETYPES_SUCCESS = 'projects/fetchFileTypesSuccess'
export const FETCH_IMPORT_URLS_ERROR = 'projects/fetchImportUrlsError'
export const FETCH_IMPORT_URLS_INIT = 'projects/fetchImportUrlsInit'
export const FETCH_IMPORT_URLS_SUCCESS = 'projects/fetchImportUrlsSuccess'
export const FETCH_OVERLAYS_ERROR = 'projects/fetchOverlaysError'
export const FETCH_OVERLAYS_INIT = 'projects/fetchOverlaysInit'
export const FETCH_OVERLAYS_SUCCESS = 'projects/fetchOverlaysSuccess'
export const NEXT_OVERLAY_ERROR = 'projects/setOverlayError'
export const NEXT_OVERLAY_INIT = 'projects/setOverlayInit'
export const NEXT_OVERLAY_SUCCESS = 'projects/setOverlaySuccess'
export const DISMISS_OVERLAY_ERROR = 'projects/dismissOverlayError'
export const DISMISS_OVERLAY_INIT = 'projects/dismissOverlayInit'
export const DISMISS_OVERLAY_SUCCESS = 'projects/dismissOverlaySuccess'
77 changes: 76 additions & 1 deletion rdmo/projects/assets/js/actions/projectsActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { FETCH_PROJECTS_ERROR, FETCH_PROJECTS_INIT, FETCH_PROJECTS_SUCCESS,
FETCH_CATALOGS_ERROR, FETCH_CATALOGS_INIT, FETCH_CATALOGS_SUCCESS,
FETCH_FILETYPES_ERROR, FETCH_FILETYPES_INIT, FETCH_FILETYPES_SUCCESS,
FETCH_IMPORT_URLS_ERROR, FETCH_IMPORT_URLS_INIT, FETCH_IMPORT_URLS_SUCCESS,
UPLOAD_PROJECT_ERROR, UPLOAD_PROJECT_INIT, UPLOAD_PROJECT_SUCCESS }
FETCH_OVERLAYS_ERROR, FETCH_OVERLAYS_INIT, FETCH_OVERLAYS_SUCCESS,
UPLOAD_PROJECT_ERROR, UPLOAD_PROJECT_INIT, UPLOAD_PROJECT_SUCCESS,
NEXT_OVERLAY_ERROR, NEXT_OVERLAY_INIT, NEXT_OVERLAY_SUCCESS,
DISMISS_OVERLAY_ERROR, DISMISS_OVERLAY_INIT, DISMISS_OVERLAY_SUCCESS}
from './actionTypes'

export function fetchAllProjects() {
Expand Down Expand Up @@ -151,3 +154,75 @@ export function uploadProjectSuccess(project) {
export function uploadProjectError(error) {
return {type: UPLOAD_PROJECT_ERROR, error}
}

export function getOverlayData() {
return function(dispatch) {
dispatch(getOverlayDataInit())
const action = (dispatch) => ProjectsApi.fetchOverlayData()
.then(overlay => {
dispatch(getOverlayDataSuccess({ overlay }))})

return dispatch(action)
.catch(error => dispatch(getOverlayDataError(error)))
}
}

export function getOverlayDataInit() {
return {type: FETCH_OVERLAYS_INIT}
}

export function getOverlayDataSuccess(overlay) {
return {type: FETCH_OVERLAYS_SUCCESS, overlay: overlay.overlay}
}

export function getOverlayDataError(error) {
return {type: FETCH_OVERLAYS_ERROR, error}
}

export function nextOverlay() {
return function(dispatch) {
dispatch(nextOverlayInit())

return ProjectsApi.setNextOverlay()
.then(overlay => dispatch(nextOverlaySuccess(overlay)))
.catch(error => {
dispatch(nextOverlayError(error))
})
}
}

export function nextOverlayInit() {
return {type: NEXT_OVERLAY_INIT}
}

export function nextOverlaySuccess(overlay) {
return {type: NEXT_OVERLAY_SUCCESS, overlay}
}

export function nextOverlayError(error) {
return {type: NEXT_OVERLAY_ERROR, error}
}

export function dismissOverlay() {
return function(dispatch) {
dispatch(dismissOverlayInit())

return ProjectsApi.dismissOverlay()
.then(overlay => dispatch(dismissOverlaySuccess(overlay)))
.catch(error => {
dispatch(dismissOverlayError(error))
})
}
}

export function dismissOverlayInit() {
return {type: DISMISS_OVERLAY_INIT}
}

export function dismissOverlaySuccess(overlay) {
return {type: DISMISS_OVERLAY_SUCCESS, overlay}
}

export function dismissOverlayError(error) {
return {type: DISMISS_OVERLAY_ERROR, error}
}
44 changes: 44 additions & 0 deletions rdmo/projects/assets/js/api/ProjectsApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,50 @@ class ProjectsApi extends BaseApi {
})
}

static fetchOverlayData() {
return fetch('/api/v1/overlays/overlays/projects/current/', {
method: 'POST',
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
}
}).then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error(response.statusText)
}
})
}

static setNextOverlay() {
return fetch('/api/v1/overlays/overlays/projects/next/', {
method: 'POST',
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
}
}).then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error(response.statusText)
}
})
}

static dismissOverlay() {
return fetch('/api/v1/overlays/overlays/projects/dismiss/', {
method: 'POST',
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
}
}).then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error(response.statusText)
}
})
}
}

export default ProjectsApi
57 changes: 57 additions & 0 deletions rdmo/projects/assets/js/components/helper/ProjectsPopover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Overlay, Popover } from 'react-bootstrap'

import { getOverlay } from '../../utils'

const ProjectsPopover = ({ last, overlay, projectsActions, setCurrentOverlay, show = true, target }) => {
if (show === false) {
return null
}

const { content, id, order, placement, title } = getOverlay({ id: overlay })

const handleDismiss = () => {
setCurrentOverlay({'overlay': '', 'last': false})
projectsActions.dismissOverlay()
}

const handleNext = () => {
const nextOverlay = getOverlay({ order: order + 1})
setCurrentOverlay({'overlay': nextOverlay.id, 'last': nextOverlay.order === 4 ? true : false})
projectsActions.nextOverlay()
}

return (
<Overlay
show={show}
placement={placement}
container={target}
>
<Popover
id={id}
placement={placement}
title={title}
>
<div>{content}</div>
<div className="popover-buttons">
<button type="button" className={`btn btn-sm popover-dismiss ${last ? 'btn-primary' : ''}`} onClick={handleDismiss} title="Dismiss all tips on this page">{gettext('Dismiss')}</button>
{!last &&
<button type="button" className="btn btn-primary btn-sm popover-next" onClick={handleNext}>{gettext('Next tip')}</button>
}
</div>
</Popover>
</Overlay>
)
}

ProjectsPopover.propTypes = {
last: PropTypes.bool,
overlay: PropTypes.string.isRequired,
projectsActions: PropTypes.object,
setCurrentOverlay: PropTypes.func,
show: PropTypes.bool,
target: PropTypes.instanceOf(Element),
}

export default ProjectsPopover
1 change: 1 addition & 0 deletions rdmo/projects/assets/js/components/helper/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as PendingInvitations } from './PendingInvitations'
export { default as ProjectFilters } from './ProjectFilters'
export { default as ProjectImport } from './ProjectImport'
export { default as ProjectsPopover } from './ProjectsPopover'
export { default as Table } from './Table'
75 changes: 52 additions & 23 deletions rdmo/projects/assets/js/components/main/Projects.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import React, { useRef, useState } from 'react'
import PropTypes from 'prop-types'
import { PendingInvitations, ProjectFilters, ProjectImport, Table } from '../helper'
import { PendingInvitations, ProjectFilters, ProjectImport, ProjectsPopover, Table } from '../helper'
import { Link, Modal, SearchField } from 'rdmo/core/assets/js/components'
import { useFormattedDateTime, useModal, useScrollToTop } from 'rdmo/core/assets/js/hooks'
import useDatePicker from '../../hooks/useDatePicker'
Expand All @@ -9,11 +9,19 @@ import { getTitlePath, getUserRoles, userIsManager, HEADER_FORMATTERS, SORTABLE_
import { get, isEmpty } from 'lodash'

const Projects = ({ config, configActions, currentUserObject, projectsActions, projectsObject }) => {
const { allowedTypes, catalogs, importUrls, invites, projects } = projectsObject

const { allowedTypes, catalogs, importUrls, invites, overlay, projects } = projectsObject
const { currentUser } = currentUserObject
const { myProjects } = config

const [currentOverlay, setCurrentOverlay] = useState(overlay)

const refs = {
'projects-table': useRef(null),
'create-project': useRef(null),
'import-project': useRef(null),
'support-info': useRef(null),
}

const { showTopButton, scrollToTop } = useScrollToTop()

const { show: showInvitations, open: openInvitations, close: closeInvitations } = useModal()
Expand Down Expand Up @@ -171,12 +179,18 @@ const Projects = ({ config, configActions, currentUserObject, projectsActions, p
</button>
)
}
<button className="btn btn-link" onClick={openImport}>
<i className="fa fa-download" aria-hidden="true"></i> {gettext('Import project')}
</button>
<button className="btn btn-link" onClick={handleNew}>
<i className="fa fa-plus" aria-hidden="true"></i> {gettext('New project')}
</button>
<div style={{ position: 'relative' }}>
<button className="btn btn-link" onClick={openImport}>
<i className="fa fa-download" aria-hidden="true"></i> {gettext('Import project')}
</button>
<div ref={refs['import-project']} style={{ position: 'absolute' }}></div>
</div>
<div style={{ position: 'relative' }}>
<button className="btn btn-link" onClick={handleNew}>
<i className="fa fa-plus" aria-hidden="true"></i> {gettext('New project')}
</button>
<div ref={refs['create-project']} style={{ position: 'absolute' }}></div>
</div>
</div>
</div>
<div className="projects-form">
Expand Down Expand Up @@ -216,19 +230,25 @@ const Projects = ({ config, configActions, currentUserObject, projectsActions, p
</Link>
</div>
</div>
<Table
cellFormatters={cellFormatters}
columnWidths={columnWidths}
config={config}
configActions={configActions}
data={projects}
headerFormatters={HEADER_FORMATTERS}
projectsActions={projectsActions}
showTopButton={showTopButton}
scrollToTop={scrollToTop}
sortableColumns={SORTABLE_COLUMNS}
visibleColumns={visibleColumns}
/>
<div>
<div style={{ position: 'relative' }}>
<div ref={refs['projects-table']} style={{ position: 'absolute' }}></div>
<Table
cellFormatters={cellFormatters}
columnWidths={columnWidths}
config={config}
configActions={configActions}
data={projects}
headerFormatters={HEADER_FORMATTERS}
projectsActions={projectsActions}
showTopButton={showTopButton}
scrollToTop={scrollToTop}
sortableColumns={SORTABLE_COLUMNS}
visibleColumns={visibleColumns}
/>
<div ref={refs['support-info']} style={{ position: 'absolute' }}></div>
</div>
</div>
<Modal {...invitationsModalProps}>
<PendingInvitations invitations={invites} />
</Modal>
Expand All @@ -238,6 +258,15 @@ const Projects = ({ config, configActions, currentUserObject, projectsActions, p
handleImport={handleImport}
importUrls={importUrls ?? []} />
</Modal>

{ currentOverlay.overlay &&
<ProjectsPopover
{...currentOverlay}
projectsActions={projectsActions}
setCurrentOverlay={setCurrentOverlay}
target={refs[currentOverlay.overlay].current}
/>
}
</div>
)
}
Expand Down
21 changes: 14 additions & 7 deletions rdmo/projects/assets/js/reducers/projectsReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { FETCH_PROJECTS_ERROR, FETCH_PROJECTS_INIT, FETCH_PROJECTS_SUCCESS,
FETCH_INVITATIONS_ERROR, FETCH_INVITATIONS_INIT, FETCH_INVITATIONS_SUCCESS,
FETCH_CATALOGS_ERROR, FETCH_CATALOGS_INIT, FETCH_CATALOGS_SUCCESS,
FETCH_FILETYPES_ERROR, FETCH_FILETYPES_INIT, FETCH_FILETYPES_SUCCESS,
FETCH_IMPORT_URLS_ERROR, FETCH_IMPORT_URLS_INIT, FETCH_IMPORT_URLS_SUCCESS
FETCH_IMPORT_URLS_ERROR, FETCH_IMPORT_URLS_INIT, FETCH_IMPORT_URLS_SUCCESS,
FETCH_OVERLAYS_ERROR, FETCH_OVERLAYS_INIT, FETCH_OVERLAYS_SUCCESS
} from '../actions/actionTypes'

const initialState = {
Expand Down Expand Up @@ -36,12 +37,18 @@ export default function projectsReducer(state = initialState, action) {
return {...state, ...action.allowedTypes}
case FETCH_FILETYPES_ERROR:
return {...state, errors: action.error.errors}
case FETCH_IMPORT_URLS_INIT:
return {...state, ...action.importUrls}
case FETCH_IMPORT_URLS_SUCCESS:
return {...state, ...action.importUrls}
case FETCH_IMPORT_URLS_ERROR:
return {...state, errors: action.error.errors}
case FETCH_IMPORT_URLS_INIT:
return {...state, ...action.importUrls}
case FETCH_IMPORT_URLS_SUCCESS:
return {...state, ...action.importUrls}
case FETCH_IMPORT_URLS_ERROR:
return {...state, errors: action.error.errors}
case FETCH_OVERLAYS_INIT:
return {...state, ...action.overlay}
case FETCH_OVERLAYS_SUCCESS:
return {...state, overlay: action.overlay}
case FETCH_OVERLAYS_ERROR:
return {...state, errors: {...state.errors, overlays: action.error.errors}, ready: false}
default:
return state
}
Expand Down
1 change: 1 addition & 0 deletions rdmo/projects/assets/js/store/configureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export default function configureStore() {
store.dispatch(projectsActions.fetchCatalogs())
store.dispatch(projectsActions.fetchAllowedFileTypes())
store.dispatch(projectsActions.fetchImportUrls())
store.dispatch(projectsActions.getOverlayData())
})
})

Expand Down
18 changes: 18 additions & 0 deletions rdmo/projects/assets/js/utils/getOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { language } from 'rdmo/core/assets/js/utils'
import OVERLAYS from './overlays'

const getOverlay = ({ order, id }) => {
const overlay = OVERLAYS.find(config => (id ? config.id === id : config.order === order))

if (overlay) {
return {
...overlay,
content: overlay.content[language],
title: overlay.title[language]
}
}

return null
}

export default getOverlay
4 changes: 3 additions & 1 deletion rdmo/projects/assets/js/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from './constants'
export { default as getOverlay } from './getOverlay'
export * from './getProjectTitlePath'
export { default as getUserRoles } from './getUserRoles'
export { default as userIsManager } from './userIsManager'
export { default as OVERLAYS } from './overlays'
export { default as TRANSLATIONS } from './translations'
export { default as userIsManager } from './userIsManager'
Loading

0 comments on commit 5d2ee04

Please sign in to comment.