Skip to content
This repository has been archived by the owner on Jul 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1869 from yjyoo773/PORTALS-2382
Browse files Browse the repository at this point in the history
PORTALS-2382: tag user or team in markdown editor
  • Loading branch information
yjyoo773 authored Oct 28, 2022
2 parents e60f46a + 83ca007 commit 9814da5
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 3 deletions.
40 changes: 37 additions & 3 deletions src/lib/containers/markdown/MarkdownEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {
} from '../../utils/synapseTypes/MarkdownCommands'
import IconSvg from '../IconSvg'
import MarkdownSynapse from './MarkdownSynapse'
import { UserMentionModal } from './UserMentionModal'
import { startCase } from 'lodash-es'
import Tooltip from '../../utils/tooltip/Tooltip'

export enum MarkdownEditorTabs {
WRITE = 'WRITE',
Expand All @@ -24,6 +27,7 @@ export const MarkdownEditor: React.FunctionComponent<MarkdownEditorProps> = ({
)
const [text, setText] = useState<string>('')
const [selectionStart, setSelectionStart] = useState<number>(0)
const [isShowingTagModal, setIsShowingTagModal] = useState<boolean>(false)
const textAreaRef = useRef<HTMLTextAreaElement>(null)

/**
Expand All @@ -37,6 +41,23 @@ export const MarkdownEditor: React.FunctionComponent<MarkdownEditorProps> = ({
}
}, [textAreaRef, selectionStart])

useEffect(() => {
textAreaRef.current?.focus()
}, [isShowingTagModal])

const handleUserTag = (user: string) => {
const newText: string[] = []
const textVal = textAreaRef.current
if (textVal) {
const start = textVal?.selectionStart
const textBeforeTag = text.substring(0, start)
const textAfterTag = text.substring(start, text.length)
setSelectionStart(start + user.length + 1)
newText.push(textBeforeTag, `@${user}`, textAfterTag)
}
setText(newText.join(''))
}

const handleCommands = (command: CommandListType) => {
const textVal = textAreaRef.current
if (textVal) {
Expand All @@ -61,7 +82,7 @@ export const MarkdownEditor: React.FunctionComponent<MarkdownEditorProps> = ({
)

setText(newText.join('\r\n'))
textAreaRef.current.focus()
textVal.focus()
// adds 2 due to new line
setSelectionStart(start + openSyntax.length + 2)
break
Expand All @@ -76,7 +97,7 @@ export const MarkdownEditor: React.FunctionComponent<MarkdownEditorProps> = ({
case 'link':
case 'image': {
const newText = `${textBeforeSelection}${openSyntax}${selected}${closeSyntax}${textAfterSelection}`
textAreaRef.current.focus()
textVal.focus()
setSelectionStart(start + openSyntax.length)
setText(newText)
}
Expand Down Expand Up @@ -110,10 +131,18 @@ export const MarkdownEditor: React.FunctionComponent<MarkdownEditorProps> = ({
{commandList.map(type => {
return (
<button key={type} onClick={() => handleCommands(type)}>
<IconSvg options={{ icon: type }} />
<IconSvg options={{ icon: type, label: startCase(type) }} />
</button>
)
})}
<Tooltip placement="top" title="Mention">
<button
className="tag"
onClick={() => setIsShowingTagModal(true)}
>
@
</button>
</Tooltip>
</div>
)}
</div>
Expand All @@ -133,6 +162,11 @@ export const MarkdownEditor: React.FunctionComponent<MarkdownEditorProps> = ({
'Nothing to preview'
)}
</div>
<UserMentionModal
show={isShowingTagModal}
onClose={() => setIsShowingTagModal(false)}
handleUserTag={handleUserTag}
/>
</div>
)
}
43 changes: 43 additions & 0 deletions src/lib/containers/markdown/UserMentionModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useCallback } from 'react'
import { Modal } from 'react-bootstrap'
import { TYPE_FILTER, UserGroupHeader } from '../../utils/synapseTypes'
import UserSearchBoxV2 from '../UserSearchBoxV2'

export type UserMentionModalProps = {
show: boolean
onClose: () => void
handleUserTag: (user: string) => void
}

export const UserMentionModal: React.FC<UserMentionModalProps> = ({
show,
onClose,
handleUserTag,
}: UserMentionModalProps) => {
const onUserChange = useCallback(
(selected: string | null, header: UserGroupHeader | null) => {
if (selected && header) {
handleUserTag(header.userName)
}
onClose()
},
[onClose, handleUserTag],
)

return (
<>
<Modal show={show} onHide={onClose} backdrop="static" animation={false}>
<Modal.Header closeButton>
<Modal.Title>Find User or Team</Modal.Title>
</Modal.Header>
<Modal.Body>
<UserSearchBoxV2
placeholder="Search for a user or team name"
onChange={onUserChange}
typeFilter={TYPE_FILTER.USERS_ONLY}
/>
</Modal.Body>
</Modal>
</>
)
}

0 comments on commit 9814da5

Please sign in to comment.