• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ringcentral / ringcentral-js-widgets / 21017357600

15 Jan 2026 02:19AM UTC coverage: 61.994% (-1.1%) from 63.06%
21017357600

push

github

web-flow
misc: sync features and bugfixes from 8f9fbb5dfe (#1784)

* misc: sync crius

* chore: update babel-setting deps

* feat(core): update logger and add fromWatch

* misc: fix tsconfig

* misc: fix tsconfig

* misc: update eslint-settings and new eslint-plugin-crius package

* chore: remove ci and nx from package.json

* feat(i18n): new getAcceptLocaleMap and preudo string support

* chore: add preudo i18n

* misc(locale-loader): convert to ts, new format support

* misc(locale-settings): use ts

* chore: add format test in phone number lib

* feat(react-hooks): add more hooks

* chore: add comments

* misc: add more mock files

* misc: update test utils

* misc: update utils

* chore: update tsconfig

* misc: update i18n string, and convert to ts

* feat: update ui components, support emoji input, new video setting ui

* feat: new rcvideo v2 module

* feat: use new subscription register api

* misc(commons): update enums/interfaces

* misc: update Analytics lib

* misc: upgrade uuid and update import

* misc(commons): update formatDuration lib

* misc(test): add test steps

* chore: update tests and more feature tests

* misc: update demo project

* misc: update cli template

* misc: fix deps issue

* misc: remove glip widgets package

* misc: fix wrong import path

* misc: limit jest worker memory

* chore: use npm trusted-publishers

10285 of 18150 branches covered (56.67%)

Branch coverage included in aggregate %.

986 of 2186 new or added lines in 228 files covered. (45.11%)

44 existing lines in 23 files now uncovered.

17404 of 26514 relevant lines covered (65.64%)

167640.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.33
/packages/ringcentral-widgets/modules/ComposeTextUI/ComposeTextUI.ts
1
import Module from '@ringcentral-integration/commons/lib/di/decorators/module';
2
import { formatNumber } from '@ringcentral-integration/commons/lib/formatNumber';
3
import type { UIFunctions, UIProps } from '@ringcentral-integration/core';
4
import { RcUIModuleV2, track } from '@ringcentral-integration/core';
5

6
import type { ComposeTextPanelProps } from '../../components/ComposeTextPanel';
7

8
import type {
9
  ComposeTextUIComponentProps,
10
  Deps,
11
} from './ComposeTextUI.interface';
12

13
/**
14
 * TODO: check type correctness after migrating to @rx-ex for client
15
 */
16

17
@Module({
18
  name: 'ComposeTextUI',
19
  deps: [
20
    'Brand',
21
    'ComposeText',
22
    'ConnectivityMonitor',
23
    'ContactSearch',
24
    'Conversations',
25
    'Locale',
26
    'MessageSender',
27
    'MessageStore',
28
    'RateLimiter',
29
    'RegionSettings',
30
    'AppFeatures',
31
    'RouterInteraction',
32
    'AccountInfo',
33
  ],
34
})
35
export class ComposeTextUI extends RcUIModuleV2<Deps> {
36
  constructor(deps: Deps) {
37
    super({
348✔
38
      deps,
39
    });
40
  }
41

42
  @track((that: ComposeTextView, eventName: string, contactType: string) => {
43
    return [eventName, { contactType, location: 'SMS compose' }];
×
44
  })
45
  async triggerEventTracking(eventName: string, contactType: string) {
46
    //
47
  }
48

49
  getUIProps({
50
    inputExpandable,
51
    supportAttachment,
52
    supportEmoji = false,
429✔
53
    useRecipientsInputV2 = false,
429✔
54
    autoFocusToField,
55
    showCustomPhoneLabel = false,
429✔
56
  }: ComposeTextUIComponentProps): UIProps<ComposeTextPanelProps> {
57
    const isContentEmpty =
58
      this._deps.composeText.messageText.length === 0 &&
429✔
59
      (!this._deps.composeText.attachments ||
60
        this._deps.composeText.attachments.length === 0);
61
    return {
429✔
62
      brand: this._deps.brand.name,
63
      currentLocale: this._deps.locale.currentLocale,
64
      sendButtonDisabled:
65
        !(this._deps.composeText.ready && this._deps.messageSender.idle) ||
1,995✔
66
        isContentEmpty ||
67
        (this._deps.composeText.toNumbers.length === 0 &&
68
          this._deps.composeText.typingToNumber.length === 0) ||
69
        !this._deps.connectivityMonitor.connectivity ||
70
        this._deps.rateLimiter.throttling,
71
      senderNumbers: this._deps.messageSender.senderNumbersList,
72
      senderNumber: this._deps.composeText.senderNumber,
73
      typingToNumber: this._deps.composeText.typingToNumber,
74
      toNumbers: this._deps.composeText.toNumbers,
75
      messageText: this._deps.composeText.messageText,
76
      outboundSMS: this._deps.appFeatures.hasOutboundSMSPermission,
77
      // @ts-expect-error TS(2322): Type '{ id: string; name: string; phoneNumber: str... Remove this comment to see the full error message
78
      searchContactList: this._deps.contactSearch.sortedResult,
79
      showSpinner: !(
80
        this._deps.composeText.ready &&
2,145✔
81
        this._deps.locale.ready &&
82
        this._deps.messageSender.ready &&
83
        this._deps.appFeatures.ready &&
84
        this._deps.contactSearch.ready
85
      ),
86
      inputExpandable,
87
      attachments: this._deps.composeText.attachments,
88
      supportAttachment:
89
        supportAttachment && this._deps.appFeatures.hasSendMMSPermission,
858✔
90
      supportEmoji,
91
      useRecipientsInputV2,
92
      autoFocus: autoFocusToField,
93
      showCustomPhoneLabel,
94
    };
95
  }
96

97
  getUIFunctions({
98
    formatContactPhone = (phoneNumber) =>
45✔
99
      // @ts-expect-error TS(2322): Type 'string | null | undefined' is not assignable... Remove this comment to see the full error message
100
      formatNumber({
63✔
101
        phoneNumber,
102
        areaCode: this._deps.regionSettings.areaCode,
103
        countryCode: this._deps.regionSettings.countryCode,
104
        maxExtensionLength: this._deps.accountInfo.maxExtensionNumberLength,
105
      }),
106
    phoneTypeRenderer,
107
    phoneSourceNameRenderer,
108
    recipientsContactInfoRenderer,
109
    recipientsContactPhoneRenderer,
110
  }: ComposeTextUIComponentProps): UIFunctions<ComposeTextPanelProps> {
111
    return {
45✔
112
      triggerEventTracking: (eventName: string, contactType: string) =>
113
        this.triggerEventTracking(eventName, contactType),
×
114
      send: async (text, attachments) => {
115
        try {
30✔
116
          const responses = await this._deps.composeText.send(
30✔
117
            text,
118
            attachments,
119
          );
120
          if (!responses || responses.length === 0) {
27✔
121
            return;
6✔
122
          }
123
          // @ts-expect-error TS(2345): Argument of type Remove this comment to see the full error message
124
          this._deps.messageStore.pushMessages(responses);
21✔
125
          if (responses.length === 1) {
21!
126
            const conversationId =
127
              responses[0] &&
21✔
128
              // @ts-expect-error TS(2551): Property 'conversation' does not exist on type 'Ge... Remove this comment to see the full error message
129
              responses[0].conversation &&
130
              // @ts-expect-error TS(2551): Property 'conversation' does not exist on type 'Ge... Remove this comment to see the full error message
131
              responses[0].conversation.id;
132
            if (!conversationId) {
21!
133
              return;
×
134
            }
135
            this._deps.routerInteraction.push(
21✔
136
              `/conversations/${conversationId}`,
137
            );
138
          } else {
139
            this._deps.routerInteraction.push('/messages');
×
140
          }
141
          // @ts-expect-error TS(2345): Argument of type 'GetMessageInfoResponse[]' is not... Remove this comment to see the full error message
142
          this._deps.conversations.relateCorrespondentEntity(responses);
21✔
143
          this._deps.composeText.clean();
21✔
144
          return;
21✔
145
        } catch (err) {
146
          console.log(err);
3✔
147
        }
148
      },
149
      formatPhone: formatContactPhone,
150
      formatContactPhone,
151
      detectPhoneNumbers: async (input: string) => {
152
        const promises = input.split(/,\s*/g).map(async (item) => {
8✔
153
          item = item.trim();
14✔
154
          const isValid = await this._deps.composeText.validatePhoneNumber(
14✔
155
            item,
156
          );
157
          return isValid ? item : '';
14✔
158
        });
159
        const results = await Promise.all(promises);
8✔
160
        const detectedNumbers = results.filter((item) => !!item);
14✔
161
        detectedNumbers.forEach((phoneNumber) => {
8✔
162
          this._deps.composeText.addToNumber({
7✔
163
            phoneNumber,
164
          });
165
        });
166
        return detectedNumbers.length > 0;
8✔
167
      },
168
      searchContact: (searchString) =>
169
        this._deps.contactSearch.debouncedSearch({ searchString }),
113✔
170
      updateSenderNumber: ({ phoneNumber }) =>
171
        this._deps.composeText.updateSenderNumber(phoneNumber),
3✔
172
      updateTypingToNumber: (...args) =>
173
        // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
174
        this._deps.composeText.updateTypingToNumber(...args),
72✔
175
      cleanTypingToNumber: (...args) =>
176
        // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
177
        this._deps.composeText.cleanTypingToNumber(...args),
×
178
      // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
179
      addToNumber: (...args) => this._deps.composeText.addToNumber(...args),
×
180
      removeToNumber: (...args) =>
181
        // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
182
        this._deps.composeText.removeToNumber(...args),
×
183
      updateMessageText: (...args) =>
184
        // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
185
        this._deps.composeText.updateMessageText(...args),
32✔
186
      phoneTypeRenderer,
187
      phoneSourceNameRenderer,
188
      recipientsContactInfoRenderer,
189
      recipientsContactPhoneRenderer,
190
      addAttachments: (...args) =>
191
        // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
NEW
192
        this._deps.composeText.addAttachments(...args),
×
193
      removeAttachment: (...args) =>
194
        // @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
195
        this._deps.composeText.removeAttachment(...args),
×
196
    };
197
  }
198
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc