From ebad7578ba8236b8a4b34a1a9be9deba336a5c58 Mon Sep 17 00:00:00 2001 From: rinrub <99617143+rinrub@users.noreply.github.com> Date: Wed, 15 May 2024 11:49:27 +0200 Subject: [PATCH] added support for emojis as text --- src/components/__tests__/slider-spec.tsx | 124 ++++++++++++++++++ .../formcomponents/choice/slider-view.tsx | 48 ++++++- 2 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 src/components/__tests__/slider-spec.tsx diff --git a/src/components/__tests__/slider-spec.tsx b/src/components/__tests__/slider-spec.tsx new file mode 100644 index 00000000..b1cb4716 --- /dev/null +++ b/src/components/__tests__/slider-spec.tsx @@ -0,0 +1,124 @@ +import { + convertToEmoji, + getCodePoint, + isValidDecimal, + isValidHex, + isValidHtmlCode, + isValidUnicodeHex, +} from '../formcomponents/choice/slider-view'; + +// Tests for validation functions +describe('Validation functions', () => { + test('isValidDecimal', () => { + expect(isValidDecimal('123')).toBe(true); + expect(isValidDecimal('abc')).toBe(false); + expect(isValidDecimal('123abc')).toBe(false); + expect(isValidDecimal('')).toBe(false); + }); + + test('isValidHtmlCode', () => { + expect(isValidHtmlCode('😀')).toBe(true); + expect(isValidHtmlCode('😀')).toBe(true); + expect(isValidHtmlCode('{abc;')).toBe(false); + expect(isValidHtmlCode('&128512;')).toBe(false); + expect(isValidHtmlCode('&#abc;')).toBe(false); + expect(isValidHtmlCode('')).toBe(false); + }); + + test('isValidHex', () => { + // Valid hex values + expect(isValidHex('0x1F600')).toBe(true); + expect(isValidHex('1F600')).toBe(true); + expect(isValidHex('123')).toBe(true); + expect(isValidHex('abc')).toBe(true); + expect(isValidHex('123abc')).toBe(true); + + // Invalid hex values + expect(isValidHex('0xGHI')).toBe(false); + expect(isValidHex('GHI')).toBe(false); + expect(isValidHex('')).toBe(false); + expect(isValidHex('0x')).toBe(false); + expect(isValidHex('0x1F6001')).toBe(true); + expect(isValidHex('1F6001')).toBe(true); + }); + + test('isValidUnicodeHex', () => { + // Valid Unicode hex values + expect(isValidUnicodeHex('U+1F600')).toBe(true); + expect(isValidUnicodeHex('U+1234')).toBe(true); + + // Invalid Unicode hex values + expect(isValidUnicodeHex('1F600')).toBe(false); + expect(isValidUnicodeHex('U+GHI')).toBe(false); + expect(isValidUnicodeHex('U+abc')).toBe(false); + expect(isValidUnicodeHex('')).toBe(false); + expect(isValidUnicodeHex('U+123')).toBe(false); + expect(isValidUnicodeHex('U+1F6001')).toBe(true); + }); +}); + +// Tests for getCodePoint function +describe('getCodePoint', () => { + test('decimal input', () => { + expect(getCodePoint('128512')).toBe(128512); + }); + + test('hex input with 0x', () => { + expect(getCodePoint('0x1F600')).toBe(0x1f600); + }); + + test('hex input without 0x', () => { + expect(getCodePoint('1F600')).toBe(0x1f600); + }); + + test('HTML code decimal input', () => { + expect(getCodePoint('😀')).toBe(128512); + }); + + test('HTML code hex input', () => { + expect(getCodePoint('😀')).toBe(0x1f600); + }); + + test('Unicode hex input', () => { + expect(getCodePoint('U+1F600')).toBe(0x1f600); + }); + + test('invalid input', () => { + expect(getCodePoint('')).toBeNull(); + }); +}); + +// Tests for convertToEmoji function +describe('convertToEmoji', () => { + test('valid decimal input', () => { + expect(convertToEmoji('128512')).toBe('😀'); + }); + + test('valid hex input with 0x', () => { + expect(convertToEmoji('0x1F600')).toBe('😀'); + }); + + test('valid hex input without 0x', () => { + expect(convertToEmoji('1F600')).toBe('😀'); + }); + + test('valid HTML code decimal input', () => { + expect(convertToEmoji('😀')).toBe('😀'); + }); + + test('valid HTML code hex input', () => { + expect(convertToEmoji('😀')).toBe('😀'); + }); + + test('valid Unicode hex input', () => { + expect(convertToEmoji('U+1F600')).toBe('😀'); + }); + + test('out of range input', () => { + expect(convertToEmoji('1212966')).toBe('1212966'); + }); + + test('invalid input', () => { + expect(convertToEmoji('')).toBe(''); + }); +}); diff --git a/src/components/formcomponents/choice/slider-view.tsx b/src/components/formcomponents/choice/slider-view.tsx index 1083ced3..50e0ee49 100644 --- a/src/components/formcomponents/choice/slider-view.tsx +++ b/src/components/formcomponents/choice/slider-view.tsx @@ -99,8 +99,52 @@ function getStepLabel(option: QuestionnaireItemAnswerOption, displayType: Slider } function getStepEmoji(option: QuestionnaireItemAnswerOption): string | undefined { - const emojiLabel = getExtension(ExtensionConstants.VALUESET_LABEL, option.valueCoding)?.valueString; - return emojiLabel; + const emojiLabel = getExtension(ExtensionConstants.VALUESET_LABEL, option.valueCoding)?.valueString?.trim(); + if (!emojiLabel) return undefined; + + return convertToEmoji(emojiLabel); } +export const isValidDecimal = (str: string): boolean => /^\d+$/.test(str); + +export const isValidHex = (str: string): boolean => /^(0x)?[0-9A-Fa-f]{1,6}$/.test(str); + +export const isValidHtmlCode = (str: string): boolean => /^&#(x[0-9A-Fa-f]+|\d+);$/.test(str); + +export const isValidUnicodeHex = (str: string): boolean => /^U\+[0-9A-Fa-f]{4,6}$/.test(str); + +export const getCodePoint = (value: string): number | null => { + if (isValidDecimal(value)) { + return parseInt(value, 10); + } + if (isValidHtmlCode(value)) { + if (value.startsWith('&#x')) { + return parseInt(value.replace(/^&#x|;$/g, ''), 16); + } else { + return parseInt(value.replace(/^&#|;$/g, ''), 10); + } + } + if (isValidUnicodeHex(value)) { + return parseInt(value.replace(/^U\+/, ''), 16); + } + if (isValidHex(value)) { + return parseInt(value.replace(/^0x/, ''), 16); + } + return null; +}; + +export const convertToEmoji = (value: string): string => { + const codePoint = getCodePoint(value); + + if (codePoint !== null && codePoint >= 0 && codePoint <= 0x10ffff) { + try { + return String.fromCodePoint(codePoint); + } catch (error) { + return value; + } + } else { + return value; + } +}; + export default SliderView;