Skip to content

Commit 9979c4c

Browse files
chrisalloOnestarLeebang9
authored
[CLNP-2908] Typescript error fix for hooks (#1054)
Fixes: [CLNP-2908](https://sendbird.atlassian.net/browse/CLNP-2908) [CLNP-2908]: https://sendbird.atlassian.net/browse/CLNP-2908?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --------- Co-authored-by: OnestarLee <100272033+OnestarLee@users.noreply.github.com> Co-authored-by: bang9 <gusrn1423@naver.com>
1 parent 19d3fba commit 9979c4c

File tree

244 files changed

+1396
-1370
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

244 files changed

+1396
-1370
lines changed

src/hooks/VoicePlayer/index.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,23 @@ export const VoicePlayerProvider = ({
7373
}
7474
};
7575

76-
const pause = (groupKey: string | null) => {
77-
if (currentGroupKey === groupKey && currentPlayer !== null) {
78-
logger.info('VoicePlayer: Pause playing(by group key).');
79-
currentPlayer?.pause();
80-
}
81-
if (groupKey === ALL) {
82-
logger.info('VoicePlayer: Pause playing(all).');
83-
currentPlayer?.pause();
76+
const pause = (groupKey?: string) => {
77+
if (currentPlayer) {
78+
if (groupKey === currentGroupKey) {
79+
logger.info('VoicePlayer: Pause playing(by group key).');
80+
currentPlayer.pause();
81+
} else if (groupKey === ALL) {
82+
logger.info('VoicePlayer: Pause playing(all).');
83+
currentPlayer.pause();
84+
}
85+
} else {
86+
logger.warning('VoicePlayer: No currentPlayer to pause.');
8487
}
8588
};
8689

8790
const play = ({
8891
groupKey,
89-
audioFile = null,
92+
audioFile,
9093
audioFileUrl = '',
9194
}: VoicePlayerPlayProps): void => {
9295
if (groupKey !== currentGroupKey) {
@@ -96,7 +99,7 @@ export const VoicePlayerProvider = ({
9699
// Clear the previous AudioPlayer element
97100
const voicePlayerRoot = document.getElementById(VOICE_PLAYER_ROOT_ID);
98101
const voicePlayerAudioElement = document.getElementById(VOICE_PLAYER_AUDIO_ID);
99-
if (voicePlayerAudioElement) {
102+
if (voicePlayerRoot && voicePlayerAudioElement) {
100103
voicePlayerRoot.removeChild(voicePlayerAudioElement);
101104
}
102105

src/hooks/VoicePlayer/useVoicePlayer.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react';
1+
import { useEffect } from 'react';
22
import { useVoicePlayerContext } from '.';
33
import { VOICE_PLAYER_AUDIO_ID } from '../../utils/consts';
44
import { useVoiceRecorderContext } from '../VoiceRecorder';
@@ -7,8 +7,8 @@ import { AudioUnitDefaultValue, VoicePlayerStatusType } from './dux/initialState
77
import { generateGroupKey } from './utils';
88

99
export interface UseVoicePlayerProps {
10-
key: string;
11-
channelUrl: string;
10+
key?: string;
11+
channelUrl?: string;
1212
audioFile?: File;
1313
audioFileUrl?: string;
1414
}
@@ -25,10 +25,10 @@ export interface UseVoicePlayerContext {
2525
export const useVoicePlayer = ({
2626
key = '',
2727
channelUrl = '',
28-
audioFile = null,
28+
audioFile,
2929
audioFileUrl = '',
3030
}: UseVoicePlayerProps): UseVoicePlayerContext => {
31-
const [groupKey] = useState<string>(generateGroupKey(channelUrl, key));
31+
const groupKey = generateGroupKey(channelUrl, key);
3232
const {
3333
play,
3434
pause,

src/hooks/VoiceRecorder/WebAudioUtils.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Thanks to https://codesandbox.io/s/media-recorder-api-downsampling-16k-mp3-encode-using-lame-js-forked-n1pblw
22
import { VOICE_RECORDER_AUDIO_SAMPLE_RATE } from '../../utils/consts';
3+
// @ts-ignore
34
import { WavHeader, Mp3Encoder } from '../../_externals/lamejs/lame.all';
45

5-
function encodeMp3(arrayBuffer: ArrayBuffer): WavHeader {
6+
function encodeMp3(arrayBuffer: ArrayBuffer) {
67
const wav = WavHeader.readHeader(new DataView(arrayBuffer));
78
const dataView = new Int16Array(arrayBuffer, wav.dataOffset, wav.dataLen / 2);
89
const mp3Encoder = new Mp3Encoder(wav.channels, wav.sampleRate, 128);
@@ -14,11 +15,13 @@ function encodeMp3(arrayBuffer: ArrayBuffer): WavHeader {
1415
if (wav.channels > 1) {
1516
for (let j = 0; j < samplesLeft.length; j++) {
1617
samplesLeft[j] = dataView[j * 2];
17-
samplesRight[j] = dataView[j * 2 + 1];
18+
if (samplesRight) {
19+
samplesRight[j] = dataView[j * 2 + 1];
20+
}
1821
}
1922
}
2023

21-
const dataBuffer = [];
24+
const dataBuffer: Int8Array[] = [];
2225
let remaining = samplesLeft.length;
2326
for (let i = 0; remaining >= maxSamples; i += maxSamples) {
2427
const left = samplesLeft.subarray(i, i + maxSamples);
@@ -44,7 +47,7 @@ function downsampleToWav(file: File, callback: (buffer: ArrayBuffer) => void): v
4447
const fileReader = new FileReader();
4548
fileReader.onload = function (ev) {
4649
// Decode audio
47-
audioCtx.decodeAudioData(ev.target.result as ArrayBuffer, (buffer) => {
50+
audioCtx.decodeAudioData(ev.target?.result as ArrayBuffer, (buffer) => {
4851
// this is where you down sample the audio, usually is 44100 samples per second
4952
const usingWebkit = !window.OfflineAudioContext;
5053
const offlineAudioCtx = new OfflineAudioContext(1, 16000 * buffer.duration, 16000);
@@ -55,8 +58,8 @@ function downsampleToWav(file: File, callback: (buffer: ArrayBuffer) => void): v
5558

5659
const reader = new FileReader();
5760
reader.onload = function () {
58-
const renderCompleteHandler = (evt): void => {
59-
const renderedBuffer = usingWebkit ? evt.renderedBuffer : evt;
61+
const renderCompleteHandler = (evt: OfflineAudioCompletionEvent | AudioBuffer) => {
62+
const renderedBuffer = usingWebkit ? (evt as OfflineAudioCompletionEvent).renderedBuffer : (evt as AudioBuffer);
6063
const buffer = bufferToWav(renderedBuffer, renderedBuffer.length);
6164
if (callback) {
6265
callback(buffer);
@@ -80,12 +83,12 @@ function downsampleToWav(file: File, callback: (buffer: ArrayBuffer) => void): v
8083
fileReader.readAsArrayBuffer(file);
8184
}
8285

83-
function bufferToWav(abuffer, len) {
86+
function bufferToWav(abuffer: AudioBuffer, len: number) {
8487
const numOfChan = abuffer.numberOfChannels;
8588
const length = len * numOfChan * 2 + 44;
8689
const buffer = new ArrayBuffer(length);
8790
const view = new DataView(buffer);
88-
const channels = [];
91+
const channels: any[] = [];
8992
let i = 0;
9093
let sample;
9194
let offset = 0;
@@ -105,9 +108,11 @@ function bufferToWav(abuffer, len) {
105108
setUint16(16); // 16-bit (hardcoded in this demo)
106109
setUint32(0x61746164); // "data" - chunk
107110
setUint32(length - pos - 4); // chunk length
111+
108112
// write interleaved data
109-
for (i = 0; i < abuffer.numberOfChannels; i++)
113+
for (i = 0; i < abuffer.numberOfChannels; i++) {
110114
channels.push(abuffer.getChannelData(i));
115+
}
111116

112117
while (pos < length) {
113118
for (i = 0; i < numOfChan; i++) {
@@ -122,15 +127,20 @@ function bufferToWav(abuffer, len) {
122127

123128
return buffer;
124129

125-
function setUint16(data) {
130+
function setUint16(data: number) {
126131
view.setUint16(pos, data, true);
127132
pos += 2;
128133
}
129134

130-
function setUint32(data) {
135+
function setUint32(data: number) {
131136
view.setUint32(pos, data, true);
132137
pos += 4;
133138
}
134139
}
135140

141+
export interface WebAudioUtils {
142+
downsampleToWav: typeof downsampleToWav;
143+
encodeMp3: typeof encodeMp3;
144+
}
145+
136146
export { downsampleToWav, encodeMp3 };

src/hooks/VoiceRecorder/index.tsx

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
VOICE_RECORDER_AUDIO_BIT_RATE,
1010
} from '../../utils/consts';
1111
import useSendbirdStateContext from '../useSendbirdStateContext';
12+
import { type WebAudioUtils } from './WebAudioUtils';
13+
import { noop } from '../../utils/utils';
1214

1315
// Input props of VoiceRecorder
1416
export interface VoiceRecorderProps {
@@ -22,11 +24,11 @@ export interface VoiceRecorderEventHandler {
2224

2325
// Output of VoiceRecorder
2426
export interface VoiceRecorderContext {
25-
start: (eventHandler?: VoiceRecorderEventHandler) => void,
26-
stop: () => void,
27+
start: (eventHandler?: VoiceRecorderEventHandler) => void;
28+
stop: () => void;
2729
isRecordable: boolean;
2830
}
29-
const noop = () => { /* noop */ };
31+
3032
const Context = createContext<VoiceRecorderContext>({
3133
start: noop,
3234
stop: noop,
@@ -37,13 +39,13 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
3739
const { children } = props;
3840
const { config } = useSendbirdStateContext();
3941
const { logger, groupChannel } = config;
40-
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder>(null);
42+
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
4143
const [isRecordable, setIsRecordable] = useState<boolean>(false);
4244
const [permissionWarning, setPermissionWarning] = useState<boolean>(false);
4345
const { stringSet } = useLocalization();
4446

4547
const isVoiceMessageEnabled = groupChannel.enableVoiceMessage;
46-
const [webAudioUtils, setWebAudioUtils] = useState(null);
48+
const [webAudioUtils, setWebAudioUtils] = useState<WebAudioUtils | null>(null);
4749

4850
const browserSupportMimeType = BROWSER_SUPPORT_MIME_TYPE_LIST.find((mimeType) => MediaRecorder.isTypeSupported(mimeType)) ?? '';
4951
if (isVoiceMessageEnabled && !browserSupportMimeType) {
@@ -52,13 +54,11 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
5254

5355
useEffect(() => {
5456
if (isVoiceMessageEnabled && !webAudioUtils) {
55-
import('./WebAudioUtils').then((data) => {
56-
setWebAudioUtils(data);
57-
});
57+
import('./WebAudioUtils').then((module) => setWebAudioUtils(module));
5858
}
5959
}, [isVoiceMessageEnabled, webAudioUtils]);
6060

61-
const start = useCallback((eventHandler: VoiceRecorderEventHandler): void => {
61+
const start = useCallback((eventHandler?: VoiceRecorderEventHandler): void => {
6262
if (isVoiceMessageEnabled && !webAudioUtils) {
6363
logger.error('VoiceRecorder: Recording audio processor is being loaded.');
6464
return;
@@ -95,7 +95,8 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
9595
mimeType: browserSupportMimeType,
9696
audioBitsPerSecond: VOICE_RECORDER_AUDIO_BIT_RATE,
9797
});
98-
mediaRecorder.ondataavailable = (e) => { // when recording stops
98+
// when recording stops
99+
mediaRecorder.ondataavailable = (e) => {
99100
logger.info('VoiceRecorder: Succeeded getting an available data.', e.data);
100101
const audioFile = new File([e.data], VOICE_MESSAGE_FILE_NAME, {
101102
lastModified: new Date().getTime(),
@@ -108,10 +109,11 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
108109
lastModified: new Date().getTime(),
109110
type: VOICE_MESSAGE_MIME_TYPE,
110111
});
111-
eventHandler?.onRecordingEnded(convertedAudioFile);
112+
eventHandler?.onRecordingEnded?.(convertedAudioFile);
112113
logger.info('VoiceRecorder: Succeeded converting audio file.', convertedAudioFile);
113114
});
114-
stream?.getAudioTracks?.().forEach?.(track => track?.stop());
115+
const tracks = stream.getAudioTracks();
116+
tracks.forEach((track) => track.stop());
115117
setIsRecordable(false);
116118
};
117119
mediaRecorder.onstart = eventHandler?.onRecordingStarted ?? noop;
@@ -133,22 +135,13 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
133135
}, [mediaRecorder]);
134136

135137
return (
136-
<Context.Provider value={{
137-
start,
138-
stop,
139-
isRecordable,
140-
}}>
138+
<Context.Provider value={{ start, stop, isRecordable }}>
141139
{children}
142-
{
143-
permissionWarning && (
144-
<Modal
145-
hideFooter
146-
onCancel={() => setPermissionWarning(false)}
147-
>
148-
<>{stringSet.VOICE_RECORDING_PERMISSION_DENIED}</>
149-
</Modal>
150-
)
151-
}
140+
{permissionWarning && (
141+
<Modal hideFooter onClose={() => setPermissionWarning(false)}>
142+
<>{stringSet.VOICE_RECORDING_PERMISSION_DENIED}</>
143+
</Modal>
144+
)}
152145
</Context.Provider>
153146
);
154147
};

src/hooks/VoiceRecorder/useVoiceRecorder.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { useCallback, useEffect, useState } from 'react';
1+
import { useCallback, useEffect, useRef, useState } from 'react';
22
import { VoiceRecorderEventHandler, useVoiceRecorderContext } from '.';
33
import useSendbirdStateContext from '../useSendbirdStateContext';
4+
import { noop } from '../../utils/utils';
45

56
// export interface UseVoiceRecorderProps extends VoiceRecorderEventHandler {
67
// /**
@@ -22,23 +23,21 @@ export interface UseVoiceRecorderContext {
2223
cancel: () => void;
2324
recordingLimit: number;
2425
recordingTime: number;
25-
recordedFile: File;
26+
recordedFile: File | null;
2627
recordingStatus: VoiceRecorderStatus;
2728
}
2829

29-
const noop = () => { /* noop */ };
30-
3130
export const useVoiceRecorder = ({
3231
onRecordingStarted = noop,
3332
onRecordingEnded = noop,
3433
}: VoiceRecorderEventHandler): UseVoiceRecorderContext => {
3534
const { config } = useSendbirdStateContext();
3635
const { voiceRecord } = config;
37-
const { maxRecordingTime } = voiceRecord;
36+
const maxRecordingTime = voiceRecord.maxRecordingTime;
3837
const voiceRecorder = useVoiceRecorderContext();
3938
const { isRecordable } = voiceRecorder;
4039

41-
const [recordedFile, setRecordedFile] = useState<File>(null);
40+
const [recordedFile, setRecordedFile] = useState<File | null>(null);
4241
const [recordingStatus, setRecordingStatus] = useState<VoiceRecorderStatus>(VoiceRecorderStatus.PREPARING);
4342
useEffect(() => {
4443
if (isRecordable && recordingStatus === VoiceRecorderStatus.PREPARING) {
@@ -72,11 +71,12 @@ export const useVoiceRecorder = ({
7271

7372
// Timer
7473
const [recordingTime, setRecordingTime] = useState<number>(0);
75-
let timer: ReturnType<typeof setInterval> = null;
74+
const timer = useRef<ReturnType<typeof setInterval> | null>(null);
7675
function startTimer() {
7776
stopTimer();
7877
setRecordingTime(0);
79-
const interval = setInterval(() => {
78+
79+
timer.current = setInterval(() => {
8080
setRecordingTime(prevTime => {
8181
const newTime = prevTime + 100;
8282
if (newTime > maxRecordingTime) {
@@ -85,11 +85,12 @@ export const useVoiceRecorder = ({
8585
return newTime;
8686
});
8787
}, 100);
88-
timer = interval;
8988
}
9089
function stopTimer() {
91-
clearInterval(timer);
92-
timer = null;
90+
if (timer.current) {
91+
clearInterval(timer.current);
92+
timer.current = null;
93+
}
9394
}
9495
useEffect(() => {
9596
if (recordingTime > maxRecordingTime) {

src/hooks/useThrottleCallback.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export function useThrottleCallback<T extends(...args: any[]) => void>(
1212
trailing: false,
1313
},
1414
) {
15-
const timer = useRef(null);
16-
const trailingArgs = useRef(null);
15+
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
16+
const trailingArgs = useRef<any[] | null>(null);
1717

1818
useEffect(() => {
1919
return () => {
@@ -58,8 +58,8 @@ export function throttle<T extends(...args: any[]) => void>(
5858
trailing: false,
5959
},
6060
) {
61-
let timer = null;
62-
let trailingArgs = null;
61+
let timer: ReturnType<typeof setTimeout> | null = null;
62+
let trailingArgs: null | any[] = null;
6363

6464
return ((...args: any[]) => {
6565
if (timer) {

0 commit comments

Comments
 (0)