UNPKG

@sendbird/uikit-utils

Version:

A collection of utility functions and constants for building chat UI components with Sendbird UIKit.

198 lines (169 loc) 5.37 kB
import type { Locale } from 'date-fns'; import { format, isThisYear, isToday, isYesterday } from 'date-fns'; import type { SendbirdBaseMessage } from '../types'; type TruncateMode = 'head' | 'mid' | 'tail'; type TruncateOption = { mode: TruncateMode; maxLen: number; separator: string }; const defaultOpts: TruncateOption = { mode: 'mid', maxLen: 40, separator: '...' }; /** * String truncate util * @param {string} str * @param {Object} opts Options for truncate * @param {'head' | 'mid' | 'tail'} opts.mode default "mid" * @param {number} opts.maxLen default 40 * @param {string} opts.separator default "..." * @returns {string} * */ export const truncate = (str: string, opts: Partial<TruncateOption> = defaultOpts): string => { const options = { ...defaultOpts, ...opts }; const { maxLen, mode, separator } = options; if (str.length <= maxLen) return str; if (mode === 'head') { return separator + str.slice(-maxLen); } if (mode === 'mid') { const lead = Math.ceil(maxLen / 2); const trail = Math.floor(maxLen / 2); return str.slice(0, lead) + separator + str.slice(-trail); } if (mode === 'tail') { return str.slice(0, maxLen) + separator; } throw new Error('Invalid truncate mode: ' + mode); }; /** * Count truncate util * If count exceed the limit, it comes in the form of "MAX+" * * @param {number} count * @param {number} MAX default 99 * @param {string} MAX_SUFFIX default + * @returns {string} * */ export const truncatedCount = (count: number, MAX = 99, MAX_SUFFIX = '+') => { if (count >= MAX) return `${MAX}${MAX_SUFFIX}`; return `${count}`; }; /** * Messages date separator format * * @param {Date} date * @param {Locale} [locale] * @returns {string} * */ export const getDateSeparatorFormat = (date: Date, locale?: Locale): string => { if (isThisYear(date)) return format(date, 'MMM dd, yyyy', { locale }); return format(date, 'E, MMM dd', { locale }); }; /** * Message time format * * @param {Date} date * @param {Locale} [locale] * @returns {string} * */ export const getMessageTimeFormat = (date: Date, locale?: Locale): string => { return format(date, 'p', { locale }); }; /** * Message preview title text * */ export const getMessagePreviewTitle = (message: SendbirdBaseMessage, EMPTY_USERNAME = '(No name)') => { if (message.isFileMessage() || message.isUserMessage()) { return message.sender.nickname || EMPTY_USERNAME; } if (message.isAdminMessage()) { return 'Admin'; } return EMPTY_USERNAME; }; /** * Message preview body text * */ export const getMessagePreviewBody = (message: SendbirdBaseMessage, EMPTY_MESSAGE = '') => { if (message.isFileMessage()) { const extIdx = message.name.lastIndexOf('.'); if (extIdx > -1) { const file = message.name.slice(0, extIdx); const ext = message.name.slice(extIdx); return file + ext; } return message.name; } if (message.isUserMessage()) { return message.message ?? EMPTY_MESSAGE; } if (message.isAdminMessage()) { return message.message ?? EMPTY_MESSAGE; } return EMPTY_MESSAGE; }; /** * Message preview time format * */ export const getMessagePreviewTime = (timestamp: number, locale?: Locale) => { if (isToday(timestamp)) return format(timestamp, 'p', { locale }); if (isYesterday(timestamp)) return 'Yesterday'; if (isThisYear(timestamp)) return format(timestamp, 'MMM dd', { locale }); return format(timestamp, 'yyyy/MM/dd', { locale }); }; /** * milliseconds to 00:00 format * */ export const millsToMMSS = (mills: number) => { let seconds = Math.floor(Math.max(0, mills) / 1000); const minutes = Math.floor(seconds / 60); seconds = seconds % 60; const mm = String(minutes).padStart(2, '0'); const ss = String(seconds).padStart(2, '0'); return `${mm}:${ss}`; }; /** * milliseconds to 0:00 format * */ export const millsToMSS = (mills: number) => { let seconds = Math.floor(Math.max(0, mills) / 1000); const minutes = Math.floor(seconds / 60); seconds = seconds % 60; const ss = String(seconds).padStart(2, '0'); return `${minutes}:${ss}`; }; /** * Message reply count format * If reply count is 1: 1 'reply' * If the reply count is greater than 1 : '{count} replies' * If the reply count is greater than {maxReplyCount} : '{maxReplyCount}+ replies' * */ export const getReplyCountFormat = (replyCount: number, maxReplyCount?: number) => { if (maxReplyCount && replyCount > maxReplyCount) { return `${maxReplyCount}+ replies`; } else if (replyCount === 1) { return `${replyCount} reply`; } else if (replyCount > 1) { return `${replyCount} replies`; } return ''; }; /** * Thread parent message time format * * @param {Date} date * @param {Locale} [locale] * @returns {string} * */ export const getThreadParentMessageTimeFormat = (date: Date, locale?: Locale): string => { return format(date, "MMM dd 'at' h:mm a", { locale }); }; /** * File size format * * @param {number} fileSize * @returns {string} * */ export const getReadableFileSize = (fileSize: number): string => { if (fileSize <= 0) { return '0 B'; } const units = ['B', 'KB', 'MB', 'GB', 'TB']; const digitGroups = Math.floor(Math.log10(fileSize) / Math.log10(1024)); return `${(fileSize / Math.pow(1024, digitGroups)).toFixed(1)} ${units[digitGroups]}`; };