Statistics: Support for Public Shares, various fixes (#1889)
This commit is contained in:
parent
017170c2e2
commit
2dfac887cd
@ -3,11 +3,14 @@ import type {
|
||||
ApiChannelStatistics,
|
||||
ApiGroupStatistics,
|
||||
ApiMessageStatistics,
|
||||
ApiMessagePublicForward,
|
||||
StatisticsGraph,
|
||||
StatisticsOverviewItem,
|
||||
StatisticsOverviewPercentage,
|
||||
StatisticsOverviewPeriod,
|
||||
} from '../../types';
|
||||
import { buildAvatarHash } from './chats';
|
||||
import { buildApiPeerId } from './peers';
|
||||
|
||||
export function buildChannelStatistics(stats: GramJs.stats.BroadcastStats): ApiChannelStatistics {
|
||||
return {
|
||||
@ -61,6 +64,31 @@ export function buildMessageStatistics(stats: GramJs.stats.MessageStats): ApiMes
|
||||
};
|
||||
}
|
||||
|
||||
export function buildMessagePublicForwards(
|
||||
result: GramJs.messages.TypeMessages,
|
||||
): ApiMessagePublicForward[] | undefined {
|
||||
if (!result || !('messages' in result)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return result.messages.map((message) => {
|
||||
const peerId = buildApiPeerId((message.peerId as GramJs.PeerChannel).channelId, 'channel');
|
||||
const channel = result.chats.find((p) => buildApiPeerId(p.id, 'channel') === peerId);
|
||||
|
||||
return {
|
||||
messageId: message.id,
|
||||
views: (message as GramJs.Message).views,
|
||||
title: (channel as GramJs.Channel).title,
|
||||
chat: {
|
||||
id: peerId,
|
||||
type: 'chatTypeChannel',
|
||||
username: (channel as GramJs.Channel).username,
|
||||
avatarHash: buildAvatarHash((channel as GramJs.Channel).photo),
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function buildGraph(
|
||||
result: GramJs.TypeStatsGraph, isPercentage?: boolean,
|
||||
): StatisticsGraph | undefined {
|
||||
|
||||
@ -85,7 +85,8 @@ export {
|
||||
} from './reactions';
|
||||
|
||||
export {
|
||||
fetchChannelStatistics, fetchGroupStatistics, fetchMessageStatistics, fetchStatisticsAsyncGraph,
|
||||
fetchChannelStatistics, fetchGroupStatistics, fetchMessageStatistics,
|
||||
fetchMessagePublicForwards, fetchStatisticsAsyncGraph,
|
||||
} from './statistics';
|
||||
|
||||
export {
|
||||
|
||||
@ -2,13 +2,14 @@ import BigInt from 'big-integer';
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import type {
|
||||
ApiChat, ApiChannelStatistics, ApiGroupStatistics, ApiMessageStatistics, StatisticsGraph,
|
||||
ApiChat, ApiChannelStatistics, ApiGroupStatistics, ApiMessageStatistics, ApiMessagePublicForward, StatisticsGraph,
|
||||
} from '../../types';
|
||||
|
||||
import { invokeRequest } from './client';
|
||||
import { addEntitiesWithPhotosToLocalDb } from '../helpers';
|
||||
import { buildInputEntity } from '../gramjsBuilders';
|
||||
import {
|
||||
buildChannelStatistics, buildGroupStatistics, buildMessageStatistics, buildGraph,
|
||||
buildChannelStatistics, buildGroupStatistics, buildMessageStatistics, buildMessagePublicForwards, buildGraph,
|
||||
} from '../apiBuilders/statistics';
|
||||
|
||||
export async function fetchChannelStatistics({
|
||||
@ -58,6 +59,32 @@ export async function fetchMessageStatistics({
|
||||
return buildMessageStatistics(result);
|
||||
}
|
||||
|
||||
export async function fetchMessagePublicForwards({
|
||||
chat,
|
||||
messageId,
|
||||
dcId,
|
||||
}: {
|
||||
chat: ApiChat;
|
||||
messageId: number;
|
||||
dcId?: number;
|
||||
}): Promise<ApiMessagePublicForward[] | undefined> {
|
||||
const result = await invokeRequest(new GramJs.stats.GetMessagePublicForwards({
|
||||
channel: buildInputEntity(chat.id, chat.accessHash) as GramJs.InputChannel,
|
||||
msgId: messageId,
|
||||
offsetPeer: new GramJs.InputPeerEmpty(),
|
||||
}), undefined, undefined, undefined, dcId);
|
||||
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if ('chats' in result) {
|
||||
addEntitiesWithPhotosToLocalDb(result.chats);
|
||||
}
|
||||
|
||||
return buildMessagePublicForwards(result);
|
||||
}
|
||||
|
||||
export async function fetchStatisticsAsyncGraph({
|
||||
token,
|
||||
x,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import type { ApiMessage } from './messages';
|
||||
import type { ApiChat } from './chats';
|
||||
import type { ApiMessage, ApiPhoto } from './messages';
|
||||
|
||||
export interface ApiChannelStatistics {
|
||||
growthGraph?: StatisticsGraph | string;
|
||||
@ -34,6 +35,15 @@ export interface ApiMessageStatistics {
|
||||
viewsGraph?: StatisticsGraph | string;
|
||||
forwards?: number;
|
||||
views?: number;
|
||||
publicForwards?: number;
|
||||
publicForwardsData?: ApiMessagePublicForward[];
|
||||
}
|
||||
|
||||
export interface ApiMessagePublicForward {
|
||||
messageId: number;
|
||||
views?: number;
|
||||
title?: string;
|
||||
chat: ApiChat;
|
||||
}
|
||||
|
||||
export interface StatisticsGraph {
|
||||
|
||||
@ -439,6 +439,7 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
||||
|| contentKey === HeaderContent.SharedMedia
|
||||
|| contentKey === HeaderContent.MemberList
|
||||
|| contentKey === HeaderContent.AddingMembers
|
||||
|| contentKey === HeaderContent.MessageStatistics
|
||||
|| isManagement
|
||||
);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import React, {
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import type { ApiMessageStatistics, StatisticsGraph } from '../../../api/types';
|
||||
import type { ApiMessageStatistics, ApiMessagePublicForward, StatisticsGraph } from '../../../api/types';
|
||||
import { selectChat } from '../../../global/selectors';
|
||||
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
@ -14,6 +14,7 @@ import useForceUpdate from '../../../hooks/useForceUpdate';
|
||||
|
||||
import Loading from '../../ui/Loading';
|
||||
import StatisticsOverview from './StatisticsOverview';
|
||||
import StatisticsPublicForward from './StatisticsPublicForward';
|
||||
|
||||
import './Statistics.scss';
|
||||
|
||||
@ -156,6 +157,16 @@ const Statistics: FC<OwnProps & StateProps> = ({
|
||||
<div className={buildClassName('Statistics__graph', !loadedCharts.current.includes(graph) && 'hidden')} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{Boolean(statistics.publicForwards) && (
|
||||
<div className="Statistics__public-forwards">
|
||||
<h2 className="Statistics__public-forwards-title">{lang('Stats.Message.PublicShares')}</h2>
|
||||
|
||||
{statistics.publicForwardsData!.map((item: ApiMessagePublicForward) => (
|
||||
<StatisticsPublicForward data={item} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
|
||||
&__messages {
|
||||
padding: 1rem 0.25rem;
|
||||
&__messages, &__public-forwards {
|
||||
padding: 1rem 0;
|
||||
border-top: 1px solid var(--color-borders);
|
||||
|
||||
&-title {
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
&.hidden {
|
||||
opacity: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@
|
||||
}
|
||||
|
||||
.lovely-chart--header {
|
||||
margin: 0 1rem;
|
||||
margin: 0 0.75rem;
|
||||
}
|
||||
|
||||
.lovely-chart--header,
|
||||
|
||||
@ -160,6 +160,8 @@ const Statistics: FC<OwnProps & StateProps> = ({
|
||||
);
|
||||
|
||||
loadedCharts.current.push(name);
|
||||
|
||||
containerRef.current!.children[index].classList.remove('hidden');
|
||||
});
|
||||
|
||||
forceUpdate();
|
||||
@ -180,7 +182,7 @@ const Statistics: FC<OwnProps & StateProps> = ({
|
||||
|
||||
<div ref={containerRef}>
|
||||
{graphs.map((graph) => (
|
||||
<div className={buildClassName('Statistics__graph', !loadedCharts.current.includes(graph) && 'hidden')} />
|
||||
<div key={graph} className="Statistics__graph hidden" />
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
|
||||
&__title {
|
||||
margin-right: 2em;
|
||||
padding-left: 0.25rem;
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
line-height: 30px;
|
||||
|
||||
@ -5,7 +5,7 @@ import type {
|
||||
ApiChannelStatistics, ApiGroupStatistics, ApiMessageStatistics, StatisticsOverviewItem,
|
||||
} from '../../../api/types';
|
||||
|
||||
import { formatIntegerCompact } from '../../../util/textFormat';
|
||||
import { formatInteger, formatIntegerCompact } from '../../../util/textFormat';
|
||||
import { formatFullDate } from '../../../util/dateFormat';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
@ -44,11 +44,14 @@ const GROUP_OVERVIEW: OverviewCell[][] = [
|
||||
|
||||
const MESSAGE_OVERVIEW: OverviewCell[][] = [
|
||||
[
|
||||
{ name: 'views', title: 'StatisticViews', isPlain: true },
|
||||
{ name: 'views', title: 'Stats.Message.Views', isPlain: true },
|
||||
{
|
||||
name: 'forwards', title: 'PrivateShares', isPlain: true, isApproximate: true,
|
||||
name: 'forwards', title: 'Stats.Message.PrivateShares', isPlain: true, isApproximate: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{ name: 'publicForwards', title: 'Stats.Message.PublicShares', isPlain: true },
|
||||
],
|
||||
];
|
||||
|
||||
export type OwnProps = {
|
||||
@ -103,7 +106,9 @@ const StatisticsOverview: FC<OwnProps> = ({ isGroup, isMessage, statistics }) =>
|
||||
if (cell.isPlain) {
|
||||
return (
|
||||
<td className="StatisticsOverview__table-cell">
|
||||
<b className="StatisticsOverview__table-value">{cell.isApproximate ? `≈${field}` : field}</b>
|
||||
<b className="StatisticsOverview__table-value">
|
||||
{cell.isApproximate ? `≈${formatInteger(field)}` : formatInteger(field)}
|
||||
</b>
|
||||
<h3 className="StatisticsOverview__table-heading">{lang(cell.title)}</h3>
|
||||
</td>
|
||||
);
|
||||
|
||||
25
src/components/right/statistics/StatisticsPublicForward.scss
Normal file
25
src/components/right/statistics/StatisticsPublicForward.scss
Normal file
@ -0,0 +1,25 @@
|
||||
.StatisticsPublicForward {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 0.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:hover, &:active {
|
||||
background-color: var(--color-chat-hover);
|
||||
}
|
||||
|
||||
.Avatar {
|
||||
flex-shrink: 0;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
&__title {
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
&__views {
|
||||
color: var(--color-text-meta);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
}
|
||||
41
src/components/right/statistics/StatisticsPublicForward.tsx
Normal file
41
src/components/right/statistics/StatisticsPublicForward.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, { memo, useCallback } from '../../../lib/teact/teact';
|
||||
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import { getActions } from '../../../global';
|
||||
import type { ApiMessagePublicForward } from '../../../api/types';
|
||||
|
||||
import Avatar from '../../common/Avatar';
|
||||
|
||||
import './StatisticsPublicForward.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
data: ApiMessagePublicForward;
|
||||
};
|
||||
|
||||
const StatisticsPublicForward: FC<OwnProps> = ({ data }) => {
|
||||
const lang = useLang();
|
||||
const { openChatByUsername } = getActions();
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
openChatByUsername({ username: data.chat.username, messageId: data.messageId });
|
||||
}, [data, openChatByUsername]);
|
||||
|
||||
return (
|
||||
<div className="StatisticsPublicForward" onClick={handleClick}>
|
||||
<Avatar size="medium" chat={data.chat} />
|
||||
|
||||
<div className="StatisticsPublicForward__info">
|
||||
<div className="StatisticsPublicForward__title">
|
||||
{data.title}
|
||||
</div>
|
||||
|
||||
<div className="StatisticsPublicForward__views">
|
||||
{lang('ChannelStats.ViewsCount', data.views, 'i')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(StatisticsPublicForward);
|
||||
@ -1,8 +1,7 @@
|
||||
.StatisticsRecentMessage {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
border-radius: var(--border-radius-default-small);
|
||||
padding: 0.5rem 0.75rem;
|
||||
|
||||
&:hover, &:active {
|
||||
background-color: var(--color-chat-hover);
|
||||
|
||||
@ -49,7 +49,7 @@ const StatisticsRecentMessage: FC<OwnProps> = ({ message }) => {
|
||||
{renderSummary(lang, message, mediaBlobUrl || mediaThumbnail, isRoundVideo)}
|
||||
</div>
|
||||
<div className="StatisticsRecentMessage__meta">
|
||||
{lang('ChannelStats.ViewsCount', message.views)}
|
||||
{lang('ChannelStats.ViewsCount', message.views, 'i')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -44,10 +44,16 @@ addActionHandler('loadMessageStatistics', async (global, actions, payload) => {
|
||||
global = getGlobal();
|
||||
|
||||
const { views, forwards } = selectChatMessages(global, chatId)[messageId];
|
||||
|
||||
result.views = views;
|
||||
result.forwards = forwards;
|
||||
|
||||
const dcId = chat.fullInfo!.statisticsDcId;
|
||||
const publicForwards = await callApi('fetchMessagePublicForwards', { chat, messageId, dcId });
|
||||
result.publicForwards = publicForwards?.length;
|
||||
result.publicForwardsData = publicForwards;
|
||||
|
||||
global = getGlobal();
|
||||
|
||||
setGlobal(updateMessageStatistics(global, result));
|
||||
});
|
||||
|
||||
|
||||
@ -1226,4 +1226,5 @@ folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
|
||||
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
|
||||
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
|
||||
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
|
||||
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;`;
|
||||
@ -227,6 +227,7 @@
|
||||
"stats.getBroadcastStats",
|
||||
"stats.getMegagroupStats",
|
||||
"stats.getMessageStats",
|
||||
"stats.getMessagePublicForwards",
|
||||
"stats.loadAsyncGraph",
|
||||
"messages.getAttachMenuBots",
|
||||
"messages.getAttachMenuBot",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user