import { ResponsiveLine } from '@nivo/line'; import { Box, FlexContainer, FlexItem, Skeleton, Tile } from '@rocket.chat/fuselage'; import colors from '@rocket.chat/fuselage-tokens/dist/colors.json'; import { addDays, startOfDay, differenceInDays, endOfDay, subDays, format } from 'date-fns'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useActiveUsers } from './useActiveUsers'; import DownloadDataButton from '../../../../components/dashboards/DownloadDataButton'; import CounterSet from '../../../../components/dataView/CounterSet'; import { useFormatDate } from '../../../../hooks/useFormatDate'; import EngagementDashboardCardFilter from '../EngagementDashboardCardFilter'; import LegendSymbol from '../dataView/LegendSymbol'; export type ActiveUsersSectionProps = { timezone: 'utc' | 'local'; }; const ActiveUsersSection = ({ timezone }: ActiveUsersSectionProps) => { const utc = timezone === 'utc'; const { data } = useActiveUsers({ utc }); const [ countDailyActiveUsers, diffDailyActiveUsers, countWeeklyActiveUsers, diffWeeklyActiveUsers, countMonthlyActiveUsers, diffMonthlyActiveUsers, dauValues = [], wauValues = [], mauValues = [], ] = useMemo(() => { if (!data) { return []; } const startDate = new Date(data.start); const createPoint = (i: number): { x: Date; y: number } => ({ x: startOfDay(addDays(startDate, i)), y: 0, }); const daysCount = differenceInDays(new Date(data.end), startDate); const createPoints = (): { x: Date; y: number }[] => Array.from({ length: daysCount }, (_, i) => createPoint(i)); const dauValuesLocal = createPoints(); const prevDauValue = createPoint(-1); const wauValuesLocal = createPoints(); const prevWauValue = createPoint(-1); const mauValuesLocal = createPoints(); const prevMauValue = createPoint(-1); const usersListsMap = data.month.reduce<{ [x: number]: string[] }>((map, dayData) => { const d = utc ? new Date(Date.UTC(dayData.year, dayData.month - 1, dayData.day)) : new Date(dayData.year, dayData.month - 1, dayData.day); const date = utc ? new Date(Date.UTC(dayData.year, dayData.month - 1, dayData.day, 23, 59, 59, 999)) : endOfDay(d); const dateOffset = differenceInDays(date, startDate); if (dateOffset >= 0 && dauValuesLocal[dateOffset]) { map[dateOffset] = dayData.usersList; dauValuesLocal[dateOffset].y = dayData.users; } return map; }, {}); const distributeValueOverPoints = ( usersListsMap: { [x: number]: string[] }, dateOffset: number, count: number, array: { x: Date; y: number }[], ): void => { const usersSet = new Set(); for (let k = dateOffset; count > 0; k--, count--) { if (usersListsMap[k]) { usersListsMap[k].map((userId) => usersSet.add(userId)); } } array[dateOffset].y = usersSet.size; }; for (let i = 0; i < dauValuesLocal.length; i++) { distributeValueOverPoints(usersListsMap, i, 7, wauValuesLocal); distributeValueOverPoints(usersListsMap, i, 30, mauValuesLocal); } prevWauValue.y = wauValuesLocal[dauValuesLocal.length - 2].y; prevMauValue.y = mauValuesLocal[dauValuesLocal.length - 2].y; prevDauValue.y = dauValuesLocal[dauValuesLocal.length - 2].y; return [ dauValuesLocal[dauValuesLocal.length - 1].y, dauValuesLocal[dauValuesLocal.length - 1].y - prevDauValue.y, wauValuesLocal[wauValuesLocal.length - 1].y, wauValuesLocal[wauValuesLocal.length - 1].y - prevWauValue.y, mauValuesLocal[mauValuesLocal.length - 1].y, mauValuesLocal[mauValuesLocal.length - 1].y - prevMauValue.y, dauValuesLocal, wauValuesLocal, mauValuesLocal, ]; }, [data, utc]); const formatDate = useFormatDate(); const { t } = useTranslation(); return ( <> { const values = []; for (let i = 0; i < 30; i++) { values.push([dauValues[i].x.toISOString(), dauValues[i].y, wauValues[i].y, mauValues[i].y]); } return values; }} /> , variation: diffDailyActiveUsers ?? 0, description: ( <> {t('Daily_Active_Users')} ), }, { count: countWeeklyActiveUsers ?? , variation: diffWeeklyActiveUsers ?? 0, description: ( <> {t('Weekly_Active_Users')} ), }, { count: countMonthlyActiveUsers ?? , variation: diffMonthlyActiveUsers ?? 0, description: ( <> {t('Monthly_Active_Users')} ), }, ]} /> {data ? ( format(new Date(date), 'dd/MM'), }} animate={true} motionConfig='stiff' theme={{ // TODO: Get it from theme axis: { ticks: { text: { fill: '#9EA2A8', fontFamily: 'Inter, -apple-system, system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Meiryo UI", Arial, sans-serif', fontSize: '10px', fontStyle: 'normal', fontWeight: 600, letterSpacing: '0.2px', lineHeight: '12px', }, }, }, tooltip: { container: { backgroundColor: '#1F2329', boxShadow: '0px 0px 12px rgba(47, 52, 61, 0.12), 0px 0px 2px rgba(47, 52, 61, 0.08)', borderRadius: 2, }, }, }} enableSlices='x' sliceTooltip={({ slice: { points } }) => ( {formatDate(points[0].data.x)} {points.map(({ serieId, data: { y: activeUsers } }) => ( {(serieId === 'dau' && t('DAU_value', { value: activeUsers })) || (serieId === 'wau' && t('WAU_value', { value: activeUsers })) || (serieId === 'mau' && t('MAU_value', { value: activeUsers }))} ))} )} /> ) : ( )} ); }; export default ActiveUsersSection;