|
|
@@ -1,5 +1,8 @@
|
|
|
import { type JSXElementConstructor, useCallback, useState } from 'react'
|
|
|
-import { Dropdown, MenuItem } from 'react-bootstrap'
|
|
|
+import {
|
|
|
+ Dropdown as BS3Dropdown,
|
|
|
+ MenuItem as BS3MenuItem,
|
|
|
+} from 'react-bootstrap'
|
|
|
import { useTranslation } from 'react-i18next'
|
|
|
import ControlledDropdown from '../../../shared/components/controlled-dropdown'
|
|
|
import getMeta from '../../../utils/meta'
|
|
|
@@ -10,6 +13,15 @@ import AddAffiliation, { useAddAffiliation } from './add-affiliation'
|
|
|
import { Nullable } from '../../../../../types/utils'
|
|
|
import { sendMB } from '../../../infrastructure/event-tracking'
|
|
|
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
|
|
+import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
|
|
+import {
|
|
|
+ Dropdown,
|
|
|
+ DropdownDivider,
|
|
|
+ DropdownHeader,
|
|
|
+ DropdownItem,
|
|
|
+ DropdownMenu,
|
|
|
+ DropdownToggle,
|
|
|
+} from '@/features/ui/components/bootstrap-5/dropdown-menu'
|
|
|
|
|
|
type SendTrackingEvent = {
|
|
|
dropdownMenu: string
|
|
|
@@ -30,7 +42,6 @@ type NewProjectButtonProps = {
|
|
|
id: string
|
|
|
buttonText?: string
|
|
|
className?: string
|
|
|
- menuClassName?: string
|
|
|
trackingKey?: string
|
|
|
showAddAffiliationWidget?: boolean
|
|
|
}
|
|
|
@@ -39,7 +50,6 @@ function NewProjectButton({
|
|
|
id,
|
|
|
buttonText,
|
|
|
className,
|
|
|
- menuClassName,
|
|
|
trackingKey,
|
|
|
showAddAffiliationWidget,
|
|
|
}: NewProjectButtonProps) {
|
|
|
@@ -88,7 +98,7 @@ function NewProjectButton({
|
|
|
|
|
|
const handleModalMenuClick = useCallback(
|
|
|
(
|
|
|
- e: React.MouseEvent<Record<string, unknown>>,
|
|
|
+ e: React.MouseEvent,
|
|
|
{ modalVariant, dropdownMenuEvent }: ModalMenuClickOptions
|
|
|
) => {
|
|
|
// avoid invoking the "onClick" callback on the main dropdown button
|
|
|
@@ -105,10 +115,7 @@ function NewProjectButton({
|
|
|
)
|
|
|
|
|
|
const handlePortalTemplateClick = useCallback(
|
|
|
- (
|
|
|
- e: React.MouseEvent<Record<string, unknown>>,
|
|
|
- institutionTemplateName: string
|
|
|
- ) => {
|
|
|
+ (e: React.MouseEvent, institutionTemplateName: string) => {
|
|
|
// avoid invoking the "onClick" callback on the main dropdown button
|
|
|
e.stopPropagation()
|
|
|
|
|
|
@@ -122,10 +129,7 @@ function NewProjectButton({
|
|
|
)
|
|
|
|
|
|
const handleStaticTemplateClick = useCallback(
|
|
|
- (
|
|
|
- e: React.MouseEvent<Record<string, unknown>>,
|
|
|
- templateTrackingKey: string
|
|
|
- ) => {
|
|
|
+ (e: React.MouseEvent, templateTrackingKey: string) => {
|
|
|
// avoid invoking the "onClick" callback on the main dropdown button
|
|
|
e.stopPropagation()
|
|
|
|
|
|
@@ -142,113 +146,230 @@ function NewProjectButton({
|
|
|
)
|
|
|
|
|
|
const ImportProjectFromGithubMenu: JSXElementConstructor<{
|
|
|
- onClick: (e: React.MouseEvent<Record<string, unknown>>) => void
|
|
|
+ onClick: (e: React.MouseEvent) => void
|
|
|
}> = importProjectFromGithubMenu?.import.default
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
- <ControlledDropdown
|
|
|
- id={id}
|
|
|
- className={className}
|
|
|
- onMainButtonClick={handleMainButtonClick}
|
|
|
- >
|
|
|
- <Dropdown.Toggle
|
|
|
- noCaret
|
|
|
- className="new-project-button"
|
|
|
- bsStyle="primary"
|
|
|
- >
|
|
|
- {buttonText || t('new_project')}
|
|
|
- </Dropdown.Toggle>
|
|
|
- <Dropdown.Menu className={menuClassName}>
|
|
|
- <MenuItem
|
|
|
- onClick={e =>
|
|
|
- handleModalMenuClick(e, {
|
|
|
- modalVariant: 'blank_project',
|
|
|
- dropdownMenuEvent: 'blank-project',
|
|
|
- })
|
|
|
- }
|
|
|
- >
|
|
|
- {t('blank_project')}
|
|
|
- </MenuItem>
|
|
|
- <MenuItem
|
|
|
- onClick={e =>
|
|
|
- handleModalMenuClick(e, {
|
|
|
- modalVariant: 'example_project',
|
|
|
- dropdownMenuEvent: 'example-project',
|
|
|
- })
|
|
|
- }
|
|
|
- >
|
|
|
- {t('example_project')}
|
|
|
- </MenuItem>
|
|
|
- <MenuItem
|
|
|
- onClick={e =>
|
|
|
- handleModalMenuClick(e, {
|
|
|
- modalVariant: 'upload_project',
|
|
|
- dropdownMenuEvent: 'upload-project',
|
|
|
- })
|
|
|
- }
|
|
|
- >
|
|
|
- {t('upload_project')}
|
|
|
- </MenuItem>
|
|
|
- {ImportProjectFromGithubMenu && (
|
|
|
- <ImportProjectFromGithubMenu
|
|
|
- onClick={e =>
|
|
|
- handleModalMenuClick(e, {
|
|
|
- modalVariant: 'import_from_github',
|
|
|
- dropdownMenuEvent: 'import-from-github',
|
|
|
- })
|
|
|
- }
|
|
|
- />
|
|
|
- )}
|
|
|
- {portalTemplates.length > 0 ? (
|
|
|
- <>
|
|
|
- <MenuItem divider />
|
|
|
- <MenuItem header>
|
|
|
- {`${t('institution')} ${t('templates')}`}
|
|
|
- </MenuItem>
|
|
|
- {portalTemplates.map((portalTemplate, index) => (
|
|
|
- <MenuItem
|
|
|
- key={`portal-template-${index}`}
|
|
|
- href={`${portalTemplate.url}#templates`}
|
|
|
+ <BootstrapVersionSwitcher
|
|
|
+ bs3={
|
|
|
+ <ControlledDropdown id={id} className={className}>
|
|
|
+ <BS3Dropdown.Toggle
|
|
|
+ noCaret
|
|
|
+ className="new-project-button"
|
|
|
+ bsStyle="primary"
|
|
|
+ >
|
|
|
+ {buttonText || t('new_project')}
|
|
|
+ </BS3Dropdown.Toggle>
|
|
|
+ <BS3Dropdown.Menu>
|
|
|
+ <BS3MenuItem
|
|
|
+ onClick={(e: React.MouseEvent) =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'blank_project',
|
|
|
+ dropdownMenuEvent: 'blank-project',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {t('blank_project')}
|
|
|
+ </BS3MenuItem>
|
|
|
+ <BS3MenuItem
|
|
|
+ onClick={(e: React.MouseEvent) =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'example_project',
|
|
|
+ dropdownMenuEvent: 'example-project',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {t('example_project')}
|
|
|
+ </BS3MenuItem>
|
|
|
+ <BS3MenuItem
|
|
|
+ onClick={(e: React.MouseEvent) =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'upload_project',
|
|
|
+ dropdownMenuEvent: 'upload-project',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {t('upload_project')}
|
|
|
+ </BS3MenuItem>
|
|
|
+ {ImportProjectFromGithubMenu && (
|
|
|
+ <ImportProjectFromGithubMenu
|
|
|
onClick={e =>
|
|
|
- handlePortalTemplateClick(e, portalTemplate.name)
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'import_from_github',
|
|
|
+ dropdownMenuEvent: 'import-from-github',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ {portalTemplates.length > 0 ? (
|
|
|
+ <>
|
|
|
+ <BS3MenuItem divider />
|
|
|
+ <div aria-hidden="true" className="dropdown-header">
|
|
|
+ {`${t('institution')} ${t('templates')}`}
|
|
|
+ </div>
|
|
|
+ {portalTemplates.map((portalTemplate, index) => (
|
|
|
+ <BS3MenuItem
|
|
|
+ key={`portal-template-${index}`}
|
|
|
+ href={`${portalTemplate.url}#templates`}
|
|
|
+ onClick={(e: React.MouseEvent) =>
|
|
|
+ handlePortalTemplateClick(e, portalTemplate.name)
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {portalTemplate.name}
|
|
|
+ </BS3MenuItem>
|
|
|
+ ))}
|
|
|
+ </>
|
|
|
+ ) : null}
|
|
|
+
|
|
|
+ {templateLinks && templateLinks.length > 0 && (
|
|
|
+ <>
|
|
|
+ <BS3MenuItem divider />
|
|
|
+ <div aria-hidden="true" className="dropdown-header">
|
|
|
+ {t('templates')}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ {templateLinks?.map((templateLink, index) => (
|
|
|
+ <BS3MenuItem
|
|
|
+ key={`new-project-button-template-${index}`}
|
|
|
+ href={templateLink.url}
|
|
|
+ onClick={(e: React.MouseEvent) =>
|
|
|
+ handleStaticTemplateClick(e, templateLink.trackingKey)
|
|
|
}
|
|
|
>
|
|
|
- {portalTemplate.name}
|
|
|
- </MenuItem>
|
|
|
+ {templateLink.name === 'view_all'
|
|
|
+ ? t('view_all')
|
|
|
+ : templateLink.name}
|
|
|
+ </BS3MenuItem>
|
|
|
))}
|
|
|
- </>
|
|
|
- ) : null}
|
|
|
-
|
|
|
- {templateLinks && templateLinks.length > 0 && (
|
|
|
- <>
|
|
|
- <MenuItem divider />
|
|
|
- <MenuItem header>{t('templates')}</MenuItem>
|
|
|
- </>
|
|
|
- )}
|
|
|
- {templateLinks?.map((templateLink, index) => (
|
|
|
- <MenuItem
|
|
|
- key={`new-project-button-template-${index}`}
|
|
|
- href={templateLink.url}
|
|
|
- onClick={e =>
|
|
|
- handleStaticTemplateClick(e, templateLink.trackingKey)
|
|
|
- }
|
|
|
+ {showAddAffiliationWidget && enableAddAffiliationWidget ? (
|
|
|
+ <>
|
|
|
+ <BS3MenuItem divider />
|
|
|
+ <li className="add-affiliation-mobile-wrapper">
|
|
|
+ <AddAffiliation className="is-mobile" />
|
|
|
+ </li>
|
|
|
+ </>
|
|
|
+ ) : null}
|
|
|
+ </BS3Dropdown.Menu>
|
|
|
+ </ControlledDropdown>
|
|
|
+ }
|
|
|
+ bs5={
|
|
|
+ <Dropdown className={className} onSelect={handleMainButtonClick}>
|
|
|
+ <DropdownToggle
|
|
|
+ id={id}
|
|
|
+ className="new-project-button"
|
|
|
+ variant="primary"
|
|
|
>
|
|
|
- {templateLink.name === 'view_all'
|
|
|
- ? t('view_all')
|
|
|
- : templateLink.name}
|
|
|
- </MenuItem>
|
|
|
- ))}
|
|
|
- {showAddAffiliationWidget && enableAddAffiliationWidget ? (
|
|
|
- <>
|
|
|
- <MenuItem divider />
|
|
|
- <li className="add-affiliation-mobile-wrapper">
|
|
|
- <AddAffiliation className="is-mobile" />
|
|
|
+ {buttonText || t('new_project')}
|
|
|
+ </DropdownToggle>
|
|
|
+ <DropdownMenu>
|
|
|
+ <li role="none">
|
|
|
+ <DropdownItem
|
|
|
+ onClick={e =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'blank_project',
|
|
|
+ dropdownMenuEvent: 'blank-project',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {t('blank_project')}
|
|
|
+ </DropdownItem>
|
|
|
</li>
|
|
|
- </>
|
|
|
- ) : null}
|
|
|
- </Dropdown.Menu>
|
|
|
- </ControlledDropdown>
|
|
|
+ <li role="none">
|
|
|
+ <DropdownItem
|
|
|
+ onClick={e =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'example_project',
|
|
|
+ dropdownMenuEvent: 'example-project',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {t('example_project')}
|
|
|
+ </DropdownItem>
|
|
|
+ </li>
|
|
|
+ <li role="none">
|
|
|
+ <DropdownItem
|
|
|
+ onClick={e =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'upload_project',
|
|
|
+ dropdownMenuEvent: 'upload-project',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {t('upload_project')}
|
|
|
+ </DropdownItem>
|
|
|
+ </li>
|
|
|
+ <li role="none">
|
|
|
+ {ImportProjectFromGithubMenu && (
|
|
|
+ <ImportProjectFromGithubMenu
|
|
|
+ onClick={e =>
|
|
|
+ handleModalMenuClick(e, {
|
|
|
+ modalVariant: 'import_from_github',
|
|
|
+ dropdownMenuEvent: 'import-from-github',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </li>
|
|
|
+ {portalTemplates.length > 0 ? (
|
|
|
+ <>
|
|
|
+ <DropdownDivider />
|
|
|
+ <DropdownHeader aria-hidden="true">
|
|
|
+ {`${t('institution')} ${t('templates')}`}
|
|
|
+ </DropdownHeader>
|
|
|
+ {portalTemplates.map((portalTemplate, index) => (
|
|
|
+ <li role="none" key={`portal-template-${index}`}>
|
|
|
+ <DropdownItem
|
|
|
+ key={`portal-template-${index}`}
|
|
|
+ href={`${portalTemplate.url}#templates`}
|
|
|
+ onClick={e =>
|
|
|
+ handlePortalTemplateClick(e, portalTemplate.name)
|
|
|
+ }
|
|
|
+ aria-label={`${portalTemplate.name} ${t('template')}`}
|
|
|
+ >
|
|
|
+ {portalTemplate.name}
|
|
|
+ </DropdownItem>
|
|
|
+ </li>
|
|
|
+ ))}
|
|
|
+ </>
|
|
|
+ ) : null}
|
|
|
+
|
|
|
+ {templateLinks && templateLinks.length > 0 && (
|
|
|
+ <>
|
|
|
+ <DropdownDivider />
|
|
|
+ <DropdownHeader aria-hidden="true">
|
|
|
+ {t('templates')}
|
|
|
+ </DropdownHeader>
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ {templateLinks?.map((templateLink, index) => (
|
|
|
+ <li role="none" key={`new-project-button-template-${index}`}>
|
|
|
+ <DropdownItem
|
|
|
+ href={templateLink.url}
|
|
|
+ onClick={e =>
|
|
|
+ handleStaticTemplateClick(e, templateLink.trackingKey)
|
|
|
+ }
|
|
|
+ aria-label={`${templateLink.name} ${t('template')}`}
|
|
|
+ >
|
|
|
+ {templateLink.name === 'view_all'
|
|
|
+ ? t('view_all')
|
|
|
+ : templateLink.name}
|
|
|
+ </DropdownItem>
|
|
|
+ </li>
|
|
|
+ ))}
|
|
|
+ {showAddAffiliationWidget && enableAddAffiliationWidget ? (
|
|
|
+ <>
|
|
|
+ <DropdownDivider />
|
|
|
+ <li className="add-affiliation-mobile-wrapper">
|
|
|
+ <AddAffiliation className="is-mobile" />
|
|
|
+ </li>
|
|
|
+ </>
|
|
|
+ ) : null}
|
|
|
+ </DropdownMenu>
|
|
|
+ </Dropdown>
|
|
|
+ }
|
|
|
+ />
|
|
|
<NewProjectButtonModal modal={modal} onHide={() => setModal(null)} />
|
|
|
</>
|
|
|
)
|