PluginProbe
Code Snippets / 4.0.0-beta.3
Code Snippets v4.0.0-beta.3
4.0.0-beta.3 4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 All 66 releases
code-snippets / js / components / StatsMenu / StatsDashboard.tsx

StatsDashboard.tsx in Code Snippets 4.0.0-beta.3, at js/components/StatsMenu/StatsDashboard.tsx

212 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { __ } from '@wordpress/i18n'
2 import React, { useState } from 'react'
3 import { useRestAPI } from '../../hooks/useRestAPI'
4 import { REST_BASES } from '../../utils/restAPI'
5 import { isLicensed } from '../../utils/screen'
6 import { SNIPPET_SCOPE_DESCRIPTIONS } from '../../utils/snippets/snippets'
7 import { buildUrl } from '../../utils/urls'
8 import { StatsChart, TotalsStatsChart } from './StatsCharts'
9 import type { StatsChartEntry, StatsChartPreferencesSchema, StatsChartViews, StatsConfigurableChartKey, StatsSummary } from '../../types/Stats'
10 import type { SnippetCodeScope, SnippetType } from '../../types/Snippet'
11
12 export const DEFAULT_STATS_CHART_VIEWS: StatsChartViews = window.CODE_SNIPPETS?.statsChartViews ?? {
13 type: 'bar',
14 activation: 'pie',
15 conditions: 'pie',
16 location: 'bar',
17 tags: 'bar'
18 }
19
20 export const STATS_TYPE_COLORS: Readonly<Record<SnippetType, string>> = {
21 php: '#2271b1',
22 html: '#cd4510',
23 css: '#9b59b6',
24 js: '#f7d67a',
25 cond: '#22826f'
26 }
27
28 export const STATS_ACTIVATION_COLORS: Readonly<Record<string, string>> = {
29 active: '#118822',
30 inactive: '#cd4510'
31 }
32
33 export const STATS_CONDITION_COLORS: Readonly<Record<string, string>> = {
34 with: '#22826f',
35 without: '#9b59b6'
36 }
37
38 export const STATS_LOCATION_COLORS: Readonly<Record<SnippetCodeScope, string>> = {
39 'global': '#ff9800',
40 'admin': '#03c7d2',
41 'front-end': '#d46f4d',
42 'single-use': '#00bcd4',
43 'content': '#2271b1',
44 'head-content': '#5865f2',
45 'body-content': '#3b5998',
46 'footer-content': '#9b59b6',
47 'admin-css': '#22826f',
48 'site-css': '#cd4510',
49 'site-head-js': '#f7d67a',
50 'site-footer-js': '#2b71a3'
51 }
52
53 interface StaticChartProps {
54 summary: StatsSummary
55 }
56
57 interface ConfigurableChartProps<Chart extends StatsConfigurableChartKey> extends StaticChartProps {
58 view: StatsChartViews[Chart]
59 setView: (view: StatsChartViews[Chart]) => void
60 }
61
62 const SnippetTypeChart: React.FC<ConfigurableChartProps<'type'>> = ({ summary, view, setView }) =>
63 <StatsChart
64 chart="type"
65 title={__('Snippet type', 'code-snippets')}
66 entries={Object.fromEntries(
67 Object.entries(summary.typeCounts).map(([type, entry]) =>
68 [type, { ...entry, url: buildUrl(window.CODE_SNIPPETS?.urls.manage, { subpage: 'snippets', type }) }])
69 )}
70 colors={STATS_TYPE_COLORS}
71 views={['pie', 'bar']}
72 view={view}
73 setView={setView}
74 />
75
76 const ActivationStatusChart: React.FC<ConfigurableChartProps<'activation'>> = ({ summary, view, setView }) =>
77 <StatsChart
78 chart="activation"
79 title={__('Activation status', 'code-snippets')}
80 entries={{
81 active: {
82 label: __('Active', 'code-snippets'),
83 count: summary.active,
84 url: buildUrl(window.CODE_SNIPPETS?.urls.manage, { subpage: 'snippets', status: 'active' })
85 },
86 inactive: {
87 label: __('Inactive', 'code-snippets'),
88 count: summary.inactive,
89 url: buildUrl(window.CODE_SNIPPETS?.urls.manage, { subpage: 'snippets', status: 'inactive' })
90 }
91 }}
92 colors={STATS_ACTIVATION_COLORS}
93 views={['pie', 'bar']}
94 view={view}
95 setView={setView}
96 />
97
98 const ConditionUsageChart: React.FC<ConfigurableChartProps<'conditions'>> = ({ summary, view, setView }) => {
99 const licensed = isLicensed()
100
101 return (
102 <div className={`stats-chart-lock${licensed ? '' : ' is-locked'}`}>
103 <StatsChart
104 chart="conditions"
105 title={__('Condition usage', 'code-snippets')}
106 entries={summary.conditionCounts}
107 colors={STATS_CONDITION_COLORS}
108 views={['pie', 'bar']}
109 view={view}
110 setView={setView}
111 overlay={!licensed && <a className="stats-lock-link button button-primary" href="https://codesnippets.pro/pricing/">
112 {__('Go Pro', 'code-snippets')}
113 </a>}
114 />
115 </div>
116 )
117 }
118
119 const LocationChart = ({ summary, view, setView }: ConfigurableChartProps<'location'>) => {
120 const entries: Record<string, StatsChartEntry> = Object.fromEntries(
121 Object.entries(summary.locationCounts).map(([scope, count]) =>
122 [scope, { label: SNIPPET_SCOPE_DESCRIPTIONS[scope as SnippetCodeScope], count }])
123 )
124
125 return (
126 <StatsChart
127 chart="location"
128 title={__('Location', 'code-snippets')}
129 entries={entries}
130 colors={STATS_LOCATION_COLORS}
131 views={['pie', 'bar']}
132 view={view}
133 setView={setView}
134 />
135 )
136 }
137
138 const TagsChart: React.FC<ConfigurableChartProps<'tags'>> = ({ summary, view, setView }) =>
139 <StatsChart
140 chart="tags"
141 title={__('Tags', 'code-snippets')}
142 entries={Object.fromEntries(
143 Object.entries(summary.tagCounts).map(([tag, entry]) =>
144 [tag, { ...entry, url: buildUrl(window.CODE_SNIPPETS?.urls.manage, { tag }) }])
145 )}
146 views={['bar', 'cloud']}
147 view={view}
148 setView={setView}
149 />
150
151 export interface StatsDashboardProps {
152 summary: StatsSummary
153 }
154
155 export const StatsDashboard: React.FC<StatsDashboardProps> = ({ summary }) => {
156 const { api } = useRestAPI()
157 const [chartViews, setChartViews] = useState<StatsChartViews>(DEFAULT_STATS_CHART_VIEWS)
158 const updateChartView = <Chart extends StatsConfigurableChartKey,>(chart: Chart, view: StatsChartViews[Chart]) => {
159 const views: StatsChartViews = { ...chartViews, [chart]: view }
160
161 setChartViews(views)
162
163 api.post<StatsChartPreferencesSchema, StatsChartPreferencesSchema>(REST_BASES.preferences.stats, { views })
164 .catch((error: unknown) => {
165 setChartViews(currentViews => currentViews === views ? chartViews : currentViews)
166 console.error(error)
167 })
168 }
169
170 return <>
171 <div className="snippets-page-header">
172 <h1>{__('Stats', 'code-snippets')}</h1>
173 </div>
174
175 <hr className="wp-header-end"></hr>
176
177 <section className="stats-chart-grid">
178 <TotalsStatsChart chart="total" label={__('Total snippets', 'code-snippets')} count={Number(summary.active) + Number(summary.inactive)} />
179
180 <SnippetTypeChart
181 summary={summary}
182 view={chartViews.type}
183 setView={view => updateChartView('type', view)}
184 />
185
186 <ActivationStatusChart
187 summary={summary}
188 view={chartViews.activation}
189 setView={view => updateChartView('activation', view)}
190 />
191
192 <ConditionUsageChart
193 summary={summary}
194 view={chartViews.conditions}
195 setView={view => updateChartView('conditions', view)}
196 />
197
198 <LocationChart
199 summary={summary}
200 view={chartViews.location}
201 setView={view => updateChartView('location', view)}
202 />
203
204 <TagsChart
205 summary={summary}
206 view={chartViews.tags}
207 setView={view => updateChartView('tags', view)}
208 />
209 </section>
210 </>
211 }
212