@sendbird/uikit-react
Version: 
Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
282 lines (275 loc) • 13.7 kB
JavaScript
import React__default, { createContext, useReducer, useContext } from 'react';
import { _ as __assign } from './bundle-CzBQNSmE.js';
import { l as VOICE_MESSAGE_FILE_NAME__XM4A, m as VOICE_MESSAGE_MIME_TYPE__XM4A, a as VOICE_MESSAGE_FILE_NAME, b as VOICE_MESSAGE_MIME_TYPE, n as VOICE_PLAYER_ROOT_ID, c as VOICE_PLAYER_AUDIO_ID } from './bundle-DmYFHm_s.js';
import { a as isSafari } from './bundle-B-s0FWL1.js';
import { u as useSendbird } from './bundle-DMcf5OHL.js';
var INITIALIZE_AUDIO_UNIT = 'INITIALIZE_AUDIO_UNIT';
var RESET_AUDIO_UNIT = 'RESET_AUDIO_UNIT';
var SET_CURRENT_PLAYER = 'SET_CURRENT_PLAYER';
var ON_VOICE_PLAYER_PLAY = 'ON_VOICE_PLAYER_PLAY';
var ON_VOICE_PLAYER_PAUSE = 'ON_VOICE_PLAYER_PAUSE';
var ON_CURRENT_TIME_UPDATE = 'ON_CURRENT_TIME_UPDATE';
var VOICE_PLAYER_STATUS = {
    IDLE: 'IDLE',
    PREPARING: 'PREPARING',
    PLAYING: 'PLAYING',
    PAUSED: 'PAUSED',
    COMPLETED: 'COMPLETED',
};
var AudioUnitDefaultValue = function () { return ({
    audioFile: null,
    playbackTime: 0,
    duration: 1000,
    playingStatus: VOICE_PLAYER_STATUS.IDLE,
}); };
var voicePlayerInitialState = {
    currentPlayer: null,
    currentGroupKey: '',
    audioStorage: {},
};
function voicePlayerReducer(state, action) {
    var _a, _b, _c, _d, _e;
    var _f, _g, _h, _j;
    switch (action.type) {
        case INITIALIZE_AUDIO_UNIT: {
            var groupKey = action.payload.groupKey;
            var audioUnit = (((_f = state.audioStorage) === null || _f === void 0 ? void 0 : _f[groupKey]) ? state.audioStorage[groupKey] : AudioUnitDefaultValue());
            audioUnit.playingStatus = VOICE_PLAYER_STATUS.PREPARING;
            return __assign(__assign({}, state), { audioStorage: __assign(__assign({}, state.audioStorage), (_a = {}, _a[groupKey] = audioUnit, _a)) });
        }
        case RESET_AUDIO_UNIT: {
            var groupKey = action.payload.groupKey;
            return __assign(__assign({}, state), { audioStorage: __assign(__assign({}, state.audioStorage), (_b = {}, _b[groupKey] = AudioUnitDefaultValue(), _b)) });
        }
        case SET_CURRENT_PLAYER: {
            var _k = action.payload, audioPlayer = _k.audioPlayer, groupKey = _k.groupKey;
            return __assign(__assign({}, state), { currentPlayer: audioPlayer, currentGroupKey: groupKey });
        }
        case ON_VOICE_PLAYER_PLAY: {
            var _l = action.payload, groupKey = _l.groupKey, audioFile = _l.audioFile;
            var audioUnit = (((_g = state.audioStorage) === null || _g === void 0 ? void 0 : _g[groupKey]) ? state.audioStorage[groupKey] : AudioUnitDefaultValue());
            audioUnit.audioFile = audioFile;
            audioUnit.playingStatus = VOICE_PLAYER_STATUS.PLAYING;
            return __assign(__assign({}, state), { audioStorage: __assign(__assign({}, state.audioStorage), (_c = {}, _c[groupKey] = audioUnit, _c)) });
        }
        case ON_VOICE_PLAYER_PAUSE: {
            var _m = action.payload, groupKey = _m.groupKey, duration = _m.duration, currentTime = _m.currentTime;
            var audioUnit = (((_h = state.audioStorage) === null || _h === void 0 ? void 0 : _h[groupKey]) ? state.audioStorage[groupKey] : AudioUnitDefaultValue());
            audioUnit.playingStatus = VOICE_PLAYER_STATUS.PAUSED;
            if (duration === currentTime) {
                audioUnit.playbackTime = 0;
            }
            return __assign(__assign({}, state), { audioStorage: __assign(__assign({}, state.audioStorage), (_d = {}, _d[groupKey] = audioUnit, _d)) });
        }
        case ON_CURRENT_TIME_UPDATE: {
            var groupKey = action.payload.groupKey;
            var _o = state.currentPlayer, currentTime = _o.currentTime, duration = _o.duration;
            var audioUnit = (((_j = state.audioStorage) === null || _j === void 0 ? void 0 : _j[groupKey]) ? state.audioStorage[groupKey] : AudioUnitDefaultValue());
            // sometimes the final time update is fired AFTER the pause event when audio is finished
            if (audioUnit.playbackTime === audioUnit.duration && audioUnit.playingStatus === VOICE_PLAYER_STATUS.PAUSED) {
                audioUnit.playbackTime = 0;
            }
            else if (currentTime > 0 && duration > 0) {
                audioUnit.playbackTime = currentTime;
                audioUnit.duration = duration;
            }
            return __assign(__assign({}, state), { audioStorage: __assign(__assign({}, state.audioStorage), (_e = {}, _e[groupKey] = audioUnit, _e)) });
        }
        default:
            return state;
    }
}
var generateGroupKey = function (channelUrl, key) {
    if (channelUrl === void 0) { channelUrl = ''; }
    if (key === void 0) { key = ''; }
    return ("".concat(channelUrl, "-").concat(key));
};
/**
 * Parses and returns the correct MIME type based on the browser.
 * If the browser is Safari and the file type is m4a, use 'audio/x-m4a' for the audio player.
 * Safari doesn't support 'audio/mp3' well.
 * Also, 'audio/m4a' should be converted to 'audio/x-m4a' to be correctly played in Safari.
 * @link: https://sendbird.atlassian.net/browse/CLNP-2997
 *
 * @param mimeType - The original MIME type.
 * @returns Converted file name and MIME type.
 */
var getParsedVoiceAudioFileInfo = function (mimeType) {
    if (isSafari(navigator.userAgent) && mimeType.includes('m4a')) {
        return {
            name: VOICE_MESSAGE_FILE_NAME__XM4A,
            mimeType: VOICE_MESSAGE_MIME_TYPE__XM4A,
        };
    }
    return {
        name: VOICE_MESSAGE_FILE_NAME,
        mimeType: VOICE_MESSAGE_MIME_TYPE,
    };
};
var ALL = 'ALL';
var noop = function () { };
var VoicePlayerStoreDefaultValue = {
    currentGroupKey: '',
    currentPlayer: null,
    audioStorage: {},
};
var Context = createContext({
    play: noop,
    pause: noop,
    stop: noop,
    voicePlayerStore: VoicePlayerStoreDefaultValue,
});
var VoicePlayerProvider = function (_a) {
    var children = _a.children;
    var _b = useReducer(voicePlayerReducer, voicePlayerInitialState), voicePlayerStore = _b[0], voicePlayerDispatcher = _b[1];
    var currentGroupKey = voicePlayerStore.currentGroupKey, currentPlayer = voicePlayerStore.currentPlayer, audioStorage = voicePlayerStore.audioStorage;
    var state = useSendbird().state;
    var config = state.config;
    var logger = config.logger;
    var stop = function (text) {
        if (text === void 0) { text = ''; }
        if (currentGroupKey.includes(text)) {
            logger.info('VoicePlayer: Pause playing(by text).');
            pause(currentGroupKey);
        }
    };
    var pause = function (groupKey) {
        if (currentPlayer) {
            if (groupKey === currentGroupKey) {
                logger.info('VoicePlayer: Pause playing(by group key).');
                currentPlayer.pause();
            }
            else if (groupKey === ALL) {
                logger.info('VoicePlayer: Pause playing(all).');
                currentPlayer.pause();
            }
        }
        else {
            logger.warning('VoicePlayer: No currentPlayer to pause.');
        }
    };
    var play = function (_a) {
        var groupKey = _a.groupKey, audioFile = _a.audioFile, _b = _a.audioFileUrl, audioFileUrl = _b === void 0 ? '' : _b, _c = _a.audioFileMimeType, audioFileMimeType = _c === void 0 ? VOICE_MESSAGE_MIME_TYPE : _c;
        if (groupKey !== currentGroupKey) {
            pause(currentGroupKey);
        }
        // Clear the previous AudioPlayer element
        var voicePlayerRoot = document.getElementById(VOICE_PLAYER_ROOT_ID);
        var voicePlayerAudioElement = document.getElementById(VOICE_PLAYER_AUDIO_ID);
        if (voicePlayerRoot && voicePlayerAudioElement) {
            voicePlayerRoot.removeChild(voicePlayerAudioElement);
        }
        logger.info('VoicePlayer: Start getting audio file.');
        new Promise(function (resolve, reject) {
            var _a;
            voicePlayerDispatcher({
                type: INITIALIZE_AUDIO_UNIT,
                payload: { groupKey: groupKey },
            });
            // audio file passed as a parameter
            if (audioFile) {
                logger.info('VoicePlayer: Use the audioFile instance.');
                resolve(audioFile);
                return;
            }
            // audio file from the audioStorage
            var cachedAudioFile = (_a = audioStorage === null || audioStorage === void 0 ? void 0 : audioStorage[groupKey]) === null || _a === void 0 ? void 0 : _a.audioFile;
            if (cachedAudioFile) {
                logger.info('VoicePlayer: Get from the audioStorage.');
                resolve(cachedAudioFile);
                return;
            }
            // fetch the audio file from URL
            fetch(audioFileUrl)
                .then(function (res) { return res.blob(); })
                .then(function (blob) {
                var audioFile = new File([blob], getParsedVoiceAudioFileInfo(audioFileMimeType).name, {
                    lastModified: new Date().getTime(),
                    type: getParsedVoiceAudioFileInfo(audioFileMimeType).mimeType,
                });
                resolve(audioFile);
                logger.info('VoicePlayer: Get the audioFile from URL.');
            })
                .catch(reject);
        })
            .then(function (audioFile) {
            var _a;
            var voicePlayerRoot = document.getElementById(VOICE_PLAYER_ROOT_ID);
            logger.info('VoicePlayer: Succeeded getting audio file.', { audioFile: audioFile });
            var currentAudioUnit = audioStorage[groupKey] || AudioUnitDefaultValue();
            var audioPlayer = new Audio((_a = URL === null || URL === void 0 ? void 0 : URL.createObjectURL) === null || _a === void 0 ? void 0 : _a.call(URL, audioFile));
            audioPlayer.id = VOICE_PLAYER_AUDIO_ID;
            audioPlayer.currentTime = currentAudioUnit.playbackTime;
            audioPlayer.volume = 1;
            audioPlayer.loop = false;
            audioPlayer.onplaying = function () {
                logger.info('VoicePlayer: OnPlaying event is called from audioPlayer', { groupKey: groupKey, audioPlayer: audioPlayer });
                voicePlayerDispatcher({
                    type: ON_VOICE_PLAYER_PLAY,
                    payload: { groupKey: groupKey, audioFile: audioFile },
                });
            };
            audioPlayer.onpause = function () {
                logger.info('VoicePlayer: OnPause event is called from audioPlayer', { groupKey: groupKey, audioPlayer: audioPlayer });
                voicePlayerDispatcher({
                    type: ON_VOICE_PLAYER_PAUSE,
                    payload: { groupKey: groupKey, duration: audioPlayer.duration, currentTime: audioPlayer.currentTime },
                });
            };
            audioPlayer.ontimeupdate = function () {
                voicePlayerDispatcher({
                    type: ON_CURRENT_TIME_UPDATE,
                    payload: { groupKey: groupKey },
                });
            };
            audioPlayer.onerror = function (error) {
                logger.error('VoicePlayer: Failed to load the audioFile on the audio player.', error);
                voicePlayerDispatcher({
                    type: RESET_AUDIO_UNIT,
                    payload: { groupKey: groupKey },
                });
            };
            audioPlayer.dataset.sbGroupId = groupKey;
            // clean up the previous audio player
            try {
                voicePlayerRoot === null || voicePlayerRoot === void 0 ? void 0 : voicePlayerRoot.childNodes.forEach(function (node) {
                    var _a, _b;
                    var element = node;
                    var thisGroupKey = (_a = element.dataset) === null || _a === void 0 ? void 0 : _a.sbGroupKey;
                    if (thisGroupKey !== groupKey) {
                        (_b = element === null || element === void 0 ? void 0 : element.pause) === null || _b === void 0 ? void 0 : _b.call(element);
                        voicePlayerRoot.removeChild(element);
                        logger.info('VoicePlayer: Removed other player.', { element: element });
                    }
                });
            }
            finally {
                audioPlayer === null || audioPlayer === void 0 ? void 0 : audioPlayer.play();
                voicePlayerRoot === null || voicePlayerRoot === void 0 ? void 0 : voicePlayerRoot.appendChild(audioPlayer);
                voicePlayerDispatcher({
                    type: SET_CURRENT_PLAYER,
                    payload: { groupKey: groupKey, audioPlayer: audioPlayer },
                });
                logger.info('VoicePlayer: Succeeded playing audio player.', { groupKey: groupKey, audioPlayer: audioPlayer });
            }
        })
            .catch(function (error) {
            logger.warning('VoicePlayer: Failed loading audio file with URL.', error);
            voicePlayerDispatcher({
                type: RESET_AUDIO_UNIT,
                payload: { groupKey: groupKey },
            });
        });
    };
    return (React__default.createElement(Context.Provider, { value: {
            play: play,
            pause: pause,
            stop: stop,
            voicePlayerStore: voicePlayerStore,
        } },
        React__default.createElement("div", { id: VOICE_PLAYER_ROOT_ID, style: { display: 'none' } }),
        children));
};
var useVoicePlayerContext = function () { return useContext(Context); };
export { AudioUnitDefaultValue as A, VOICE_PLAYER_STATUS as V, VoicePlayerProvider as a, ALL as b, generateGroupKey as g, useVoicePlayerContext as u };
//# sourceMappingURL=bundle-BZ_07PG_.js.map