Skip to content

Commit

Permalink
fix(comments): handle lack of access to inline comments (#5925)
Browse files Browse the repository at this point in the history
* fix(comments): display upsell UI for inline comments

* chore(core): export `UpsellDialogViewedInfo` interface

* dev(comments): update `CommentsUpsellDialogStory`

* fix(comments): change inline comment telemetry source name
  • Loading branch information
hermanwikner authored Mar 11, 2024
1 parent c531a6b commit 2d4f60c
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ interface UpsellDialogActionsInfo {
feature: 'comments' | 'scheduled_publishing' | 'ai_assist'
type: 'modal' | 'inspector'
}
interface UpsellDialogViewedInfo extends UpsellDialogActionsInfo {
source: 'field_action' | 'document_toolbar' | 'document_action' | 'navbar' | 'link'

/** @internal */
export interface UpsellDialogViewedInfo extends UpsellDialogActionsInfo {
source: 'field_action' | 'document_toolbar' | 'document_action' | 'navbar' | 'link' | 'pte'
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ function CommentFieldInner(

if (mode === 'upsell') {
if (upsellData) {
handleOpenDialog()
handleOpenDialog('field_action')
} else {
// Open the comments inspector
onCommentsOpen?.()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ import {
CommentInlineHighlightSpan,
type CommentMessage,
type CommentsTextSelectionItem,
type CommentsUIMode,
type CommentUpdatePayload,
isTextSelectionComment,
useComments,
useCommentsEnabled,
useCommentsScroll,
useCommentsSelectedPath,
useCommentsUpsell,
} from '../../../src'
import {getSelectionBoundingRect, useAuthoringReferenceElement} from '../helpers'
import {FloatingButtonPopover} from './FloatingButtonPopover'
Expand All @@ -47,22 +49,25 @@ export function CommentsPortableTextInput(props: PortableTextInputProps) {
// Therefore we disable the comments for the AI assist type.
const isAiAssist = props.schemaType.name === AI_ASSIST_TYPE

if (!enabled || mode === 'upsell' || isAiAssist) {
if (!enabled || isAiAssist) {
return props.renderDefault(props)
}

return <CommentsPortableTextInputInner {...props} />
return <CommentsPortableTextInputInner {...props} mode={mode} />
}

export const CommentsPortableTextInputInner = React.memo(function CommentsPortableTextInputInner(
props: PortableTextInputProps,
props: PortableTextInputProps & {mode: CommentsUIMode},
) {
const {mode} = props
const currentUser = useCurrentUser()
const portal = usePortal()

const {mentionOptions, comments, operation, onCommentsOpen, getComment} = useComments()
const {mentionOptions, comments, operation, onCommentsOpen, getComment, setStatus, status} =
useComments()
const {setSelectedPath, selectedPath} = useCommentsSelectedPath()
const {scrollToComment, scrollToGroup} = useCommentsScroll()
const {handleOpenDialog} = useCommentsUpsell()

const editorRef = useRef<PortableTextEditor | null>(null)
const mouseDownRef = useRef<boolean>(false)
Expand Down Expand Up @@ -100,8 +105,15 @@ export const CommentsPortableTextInputInner = React.memo(function CommentsPortab
// Set the next comment selection to the current selection so that we can
// render the comment input popover on the current selection using a range decoration.
const handleSelectCurrentSelection = useCallback(() => {
// When trying to add a comment in "upsell" mode, we want to
// display the upsell dialog instead of the comment input popover.
if (mode === 'upsell') {
handleOpenDialog('pte')
return
}

setNextCommentSelection(currentSelection)
}, [currentSelection])
}, [currentSelection, handleOpenDialog, mode])

// Clear the selection and close the popover when discarding the comment
const handleCommentDiscardConfirm = useCallback(() => {
Expand All @@ -125,12 +137,15 @@ export const CommentsPortableTextInputInner = React.memo(function CommentsPortab

const fragment = getFragment() || EMPTY_ARRAY
const editorValue = PortableTextEditor.getValue(editorRef.current)

if (!editorValue) return

const textSelection = buildTextSelectionFromFragment({
fragment,
selection: nextCommentSelection,
value: editorValue,
})

const threadId = uuid()

operation.create({
Expand All @@ -145,27 +160,37 @@ export const CommentsPortableTextInputInner = React.memo(function CommentsPortab
threadId,
})

// Open the inspector when a new comment is added
onCommentsOpen?.()

// Set the status to 'open' so that the comment is visible
if (status === 'resolved') {
setStatus('open')
}

// Set the selected path to the new comment
setSelectedPath({
fieldPath: stringFieldPath,
threadId,
origin: 'form',
})

// Scroll to the comment
scrollToGroup(threadId)

resetStates()
}, [
resetStates,
getFragment,
nextCommentSelection,
getFragment,
operation,
stringFieldPath,
nextCommentValue,
onCommentsOpen,
operation,
scrollToGroup,
status,
setSelectedPath,
stringFieldPath,
scrollToGroup,
resetStates,
setStatus,
])

const handleDecoratorClick = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {useCommentsUpsell} from '../../../hooks'
const CommentsUpsellDialogStoryInner = () => {
const {upsellData, handleOpenDialog} = useCommentsUpsell()
const handleOpen = useCallback(() => {
handleOpenDialog()
handleOpenDialog('field_action')
}, [handleOpenDialog])

useEffect(() => {
handleOpenDialog()
handleOpenDialog('field_action')
}, [handleOpenDialog])

if (!upsellData) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
UpsellDialogLearnMoreCtaClicked,
UpsellDialogUpgradeCtaClicked,
UpsellDialogViewed,
type UpsellDialogViewedInfo,
useClient,
useProjectId,
} from 'sanity'
Expand Down Expand Up @@ -123,14 +124,18 @@ export function CommentsUpsellProvider(props: {children: React.ReactNode}) {
}
}, [client, projectId])

const handleOpenDialog = useCallback(() => {
setUpsellDialogOpen(true)
telemetry.log(UpsellDialogViewed, {
feature: FEATURE,
type: 'modal',
source: 'field_action',
})
}, [telemetry])
const handleOpenDialog = useCallback(
(source: UpsellDialogViewedInfo['source']) => {
setUpsellDialogOpen(true)

telemetry.log(UpsellDialogViewed, {
feature: FEATURE,
type: 'modal',
source,
})
},
[telemetry],
)

const ctxValue = useMemo<CommentsUpsellContextValue>(
() => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {type UpsellDialogViewedInfo} from 'sanity'

import {type CommentsUpsellData} from '../../types'

export interface CommentsUpsellContextValue {
upsellDialogOpen: boolean
handleOpenDialog: () => void
handleOpenDialog: (source: UpsellDialogViewedInfo['source']) => void
upsellData: CommentsUpsellData | null
telemetryLogs: {
dialogSecondaryClicked: () => void
dialogPrimaryClicked: () => void
panelViewed: (source: 'document_action' | 'field_action' | 'link') => void
panelViewed: (source: UpsellDialogViewedInfo['source']) => void
panelDismissed: () => void
panelPrimaryClicked: () => void
panelSecondaryClicked: () => void
Expand Down

0 comments on commit 2d4f60c

Please sign in to comment.