-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix short mentions handling and bump live-markdown
- Loading branch information
Showing
7 changed files
with
245 additions
and
97 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import {useMemo} from 'react'; | ||
import {usePersonalDetails} from '@components/OnyxProvider'; | ||
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; | ||
|
||
const getMention = (mention: string) => `@${mention}`; | ||
|
||
/** | ||
* This hook returns data to be used with short mentions in LiveMarkdown/Composer. | ||
* Short mentions have the format `@username`, where username is the first part of user's login (email). | ||
* All the personal data from Onyx is formatted into short-mentions. | ||
* In addition, currently logged-in user is returned separately since it requires special styling. | ||
*/ | ||
export default function useShortMentionsList() { | ||
const personalDetails = usePersonalDetails(); | ||
const currentUserPersonalDetails = useCurrentUserPersonalDetails(); | ||
|
||
const mentionsList = useMemo(() => { | ||
if (!personalDetails) { | ||
return []; | ||
} | ||
|
||
return Object.values(personalDetails) | ||
.map((personalDetail) => { | ||
if (!personalDetail?.login) { | ||
return; | ||
} | ||
|
||
const [username] = personalDetail.login.split('@'); | ||
return username ? getMention(username) : undefined; | ||
}) | ||
.filter((login): login is string => !!login); | ||
}, [personalDetails]); | ||
|
||
const currentUserMention = useMemo(() => { | ||
if (!currentUserPersonalDetails.login) { | ||
return; | ||
} | ||
|
||
const [baseName] = currentUserPersonalDetails.login.split('@'); | ||
return getMention(baseName); | ||
}, [currentUserPersonalDetails.login]); | ||
|
||
return {mentionsList, currentUserMention}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import type {MarkdownRange} from '@expensify/react-native-live-markdown'; | ||
|
||
/** | ||
* Handles possible short mentions inside ranges by verifying if the specific range refers to a user mention/login | ||
* that is available in passed `availableMentions` list. If yes, then it gets the same styling as normal email mention. | ||
* In addition, applies special styling to current user. | ||
*/ | ||
function decorateRangesWithShortMentions(ranges: MarkdownRange[], text: string, availableMentions: string[], currentUser?: string): MarkdownRange[] { | ||
'worklet'; | ||
|
||
return ranges | ||
.map((range) => { | ||
if (range.type === 'mention-short') { | ||
const mentionText = text.slice(range.start, range.start + range.length); | ||
|
||
if (currentUser && mentionText === currentUser) { | ||
return { | ||
...range, | ||
type: 'mention-here', | ||
}; | ||
} | ||
|
||
if (availableMentions.includes(mentionText)) { | ||
return { | ||
...range, | ||
type: 'mention-user', | ||
}; | ||
} | ||
|
||
// If it's neither, we remove the range since no styling will be needed | ||
return; | ||
} | ||
return range; | ||
}) | ||
.filter((maybeRange): maybeRange is MarkdownRange => !!maybeRange); | ||
} | ||
|
||
// eslint-disable-next-line import/prefer-default-export | ||
export {decorateRangesWithShortMentions}; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import type {MarkdownRange} from '@expensify/react-native-live-markdown'; | ||
import {decorateRangesWithShortMentions} from '@libs/ParsingUtils'; | ||
|
||
describe('decorateRangesWithShortMentions', () => { | ||
test('returns empty list for empty text', () => { | ||
const result = decorateRangesWithShortMentions([], '', [], ''); | ||
expect(result).toEqual([]); | ||
}); | ||
|
||
test('returns empty list when there are no relevant mentions', () => { | ||
const text = 'Lorem ipsum'; | ||
const result = decorateRangesWithShortMentions([], text, [], ''); | ||
expect(result).toEqual([]); | ||
}); | ||
|
||
test('returns unchanged ranges when there are other markups than user-mentions', () => { | ||
const text = 'Lorem ipsum'; | ||
const ranges: MarkdownRange[] = [ | ||
{ | ||
type: 'bold', | ||
start: 5, | ||
length: 3, | ||
}, | ||
]; | ||
const result = decorateRangesWithShortMentions(ranges, text, [], ''); | ||
expect(result).toEqual([ | ||
{ | ||
type: 'bold', | ||
start: 5, | ||
length: 3, | ||
}, | ||
]); | ||
}); | ||
|
||
test('returns ranges with current user type changed to "mention-here"', () => { | ||
const text = 'Lorem ipsum @myUser'; | ||
const ranges: MarkdownRange[] = [ | ||
{ | ||
type: 'mention-short', | ||
start: 12, | ||
length: 8, | ||
}, | ||
]; | ||
const result = decorateRangesWithShortMentions(ranges, text, [], '@myUser'); | ||
expect(result).toEqual([ | ||
{ | ||
type: 'mention-here', | ||
start: 12, | ||
length: 8, | ||
}, | ||
]); | ||
}); | ||
|
||
test('returns ranges with correct short-mentions', () => { | ||
const text = 'Lorem ipsum @steven.mock'; | ||
const ranges: MarkdownRange[] = [ | ||
{ | ||
type: 'mention-short', | ||
start: 12, | ||
length: 12, | ||
}, | ||
]; | ||
const availableMentions = ['@johnDoe', '@steven.mock']; | ||
|
||
const result = decorateRangesWithShortMentions(ranges, text, availableMentions, ''); | ||
expect(result).toEqual([ | ||
{ | ||
type: 'mention-user', | ||
start: 12, | ||
length: 12, | ||
}, | ||
]); | ||
}); | ||
|
||
test('returns ranges with removed short-mentions when they do not match', () => { | ||
const text = 'Lorem ipsum @steven.mock'; | ||
const ranges: MarkdownRange[] = [ | ||
{ | ||
type: 'bold', | ||
start: 5, | ||
length: 3, | ||
}, | ||
{ | ||
type: 'mention-short', | ||
start: 12, | ||
length: 12, | ||
}, | ||
]; | ||
const availableMentions = ['@other.person']; | ||
|
||
const result = decorateRangesWithShortMentions(ranges, text, availableMentions, ''); | ||
expect(result).toEqual([ | ||
{ | ||
type: 'bold', | ||
start: 5, | ||
length: 3, | ||
}, | ||
]); | ||
}); | ||
|
||
test('returns ranges with both types of mentions handled', () => { | ||
const text = 'Lorem ipsum @steven.mock @John.current @test'; | ||
const ranges: MarkdownRange[] = [ | ||
{ | ||
type: 'bold', | ||
start: 5, | ||
length: 3, | ||
}, | ||
{ | ||
type: 'mention-short', | ||
start: 12, | ||
length: 12, | ||
}, | ||
{ | ||
type: 'mention-short', | ||
start: 25, | ||
length: 13, | ||
}, | ||
]; | ||
const availableMentions = ['@johnDoe', '@steven.mock', '@John.current']; | ||
const currentUser = '@John.current'; | ||
|
||
const result = decorateRangesWithShortMentions(ranges, text, availableMentions, currentUser); | ||
expect(result).toEqual([ | ||
{ | ||
type: 'bold', | ||
start: 5, | ||
length: 3, | ||
}, | ||
{ | ||
type: 'mention-user', | ||
start: 12, | ||
length: 12, | ||
}, | ||
{ | ||
type: 'mention-here', | ||
start: 25, | ||
length: 13, | ||
}, | ||
]); | ||
}); | ||
}); |