Skip to content

Commit 5df00c9

Browse files
feat: add offloads metrics with optional shortcuts (#970)
- Added an offload image metric box in Dashboard - Added shortcuts for PRO users to go to the corresponding settings easily.
1 parent c556bfa commit 5df00c9

File tree

5 files changed

+124
-33
lines changed

5 files changed

+124
-33
lines changed

assets/src/dashboard/parts/connected/dashboard/index.js

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import {
1313
} from '@wordpress/components';
1414

1515
import { sprintf } from '@wordpress/i18n';
16-
16+
import { useMemo } from '@wordpress/element';
1717
import { useSelect } from '@wordpress/data';
18-
import { warning, help } from '@wordpress/icons';
18+
import { warning, external, help } from '@wordpress/icons';
1919

2020
import { clearCache } from '../../../utils/api';
2121

@@ -26,40 +26,25 @@ import {
2626
bolt,
2727
update,
2828
offloadImage,
29-
settings
29+
settings,
30+
globe,
31+
arrowDownToLine,
32+
cloudDownload,
33+
chartBarDecreasing
3034
} from '../../../utils/icons';
3135

3236
import ProgressBar from '../../components/ProgressBar';
33-
import DashboardMetricBox from '../../components/DashboardMetricBox';
3437

3538
import LastImages from './LastImages';
36-
import { useMemo } from 'react';
3739

3840
const cardClasses = 'flex p-6 bg-light-blue border border-blue-300 rounded-md';
3941

40-
const metrics = [
41-
{
42-
label: optimoleDashboardApp.strings.metrics.metricsTitle2,
43-
description: optimoleDashboardApp.strings.metrics.metricsSubtitle2,
44-
value: 'saved_size'
45-
},
46-
{
47-
label: optimoleDashboardApp.strings.metrics.metricsTitle3,
48-
description: optimoleDashboardApp.strings.metrics.metricsSubtitle3,
49-
value: 'compression_percentage'
50-
},
51-
{
52-
label: optimoleDashboardApp.strings.metrics.metricsTitle4,
53-
description: optimoleDashboardApp.strings.metrics.metricsSubtitle4,
54-
value: 'traffic'
55-
}
56-
];
57-
5842
const settingsTab = {
5943
offload_image: 1,
6044
advance: 2
6145
};
6246

47+
6348
const navigate = ( tabId ) => {
6449
const links = window.optimoleDashboardApp.submenu_links;
6550
const settingsLink = links.find( link => '#settings' === link.hash );
@@ -140,6 +125,50 @@ const Dashboard = () => {
140125
};
141126
});
142127

128+
const availableMetrics = useMemo( () => {
129+
const metrics = [
130+
{
131+
icon: arrowDownToLine,
132+
label: optimoleDashboardApp.strings.metrics.metricsTitle2,
133+
description: optimoleDashboardApp.strings.metrics.metricsSubtitle2,
134+
value: 'saved_size',
135+
hasButton: true,
136+
buttonText: optimoleDashboardApp.strings.metrics.adjust_compression
137+
},
138+
{
139+
icon: chartBarDecreasing,
140+
label: optimoleDashboardApp.strings.metrics.metricsTitle3,
141+
description: optimoleDashboardApp.strings.metrics.metricsSubtitle3,
142+
value: 'compression_percentage',
143+
hasButton: true,
144+
buttonText: optimoleDashboardApp.strings.metrics.adjust_compression
145+
},
146+
{
147+
icon: globe,
148+
label: optimoleDashboardApp.strings.metrics.metricsTitle4,
149+
description: optimoleDashboardApp.strings.metrics.metricsSubtitle4,
150+
value: 'traffic',
151+
hasButton: true,
152+
buttonText: optimoleDashboardApp.strings.metrics.view_analytics
153+
}
154+
];
155+
156+
if ( userData?.can_use_offloading ) {
157+
metrics.push(
158+
{
159+
icon: cloudDownload,
160+
label: optimoleDashboardApp.strings.metrics.metricsTitle5,
161+
description: optimoleDashboardApp.strings.metrics.metricsSubtitle5,
162+
value: 'offloaded_images',
163+
hasButton: true,
164+
buttonText: optimoleDashboardApp.strings.metrics.manage_offloading
165+
}
166+
);
167+
}
168+
169+
return metrics;
170+
}, [ userData ]);
171+
143172
const visitorsLimitPercent = ( ( userData.visitors / userData.visitors_limit ) * 100 ).toFixed( 0 );
144173

145174
const renewalDate = useMemo( () => {
@@ -159,11 +188,15 @@ const Dashboard = () => {
159188

160189
// Fallback for missing data
161190
if ( undefined === value ) {
162-
value = 'saved_size' === type ?
163-
Math.floor( Math.random() * 2500000 ) + 500000 : // Mock KB
164-
'traffic' === type ?
165-
Math.floor( Math.random() * 2500 ) + 500 : // Mock MB
166-
Math.floor( Math.random() * 40 ) + 10; // Mock Percentage
191+
if ( 'saved_size' === type ) {
192+
value = Math.floor( Math.random() * 2500000 ) + 500000; // Mock KB
193+
} else if ( 'traffic' === type ) {
194+
value = Math.floor( Math.random() * 2500 ) + 500; // Mock MB
195+
} else if ( 'offloaded_images' === type ) {
196+
value = Math.floor( Math.random() * 500 ) + 50; // Mock images count
197+
} else {
198+
value = Math.floor( Math.random() * 40 ) + 10; // Mock Percentage
199+
}
167200
}
168201

169202
switch ( type ) {
@@ -196,6 +229,10 @@ const Dashboard = () => {
196229
unit = 'TB';
197230
}
198231
break;
232+
case 'offloaded_images':
233+
formattedValue = parseInt( value );
234+
unit = 1 === formattedValue ? optimoleDashboardApp.strings.metrics.image : optimoleDashboardApp.strings.metrics.images;
235+
break;
199236
default:
200237
formattedValue = parseFloat( value ).toFixed( 2 );
201238
unit = '';
@@ -204,6 +241,19 @@ const Dashboard = () => {
204241
return { formattedValue, unit };
205242
};
206243

244+
const getMetricButtonAction = ( metricValue ) => {
245+
switch ( metricValue ) {
246+
case 'saved_size':
247+
return { onClick: () => navigate( settingsTab.advance ) };
248+
case 'compression_percentage':
249+
return { onClick: () => navigate( settingsTab.advance ) };
250+
case 'traffic':
251+
return { href: window.optimoleDashboardApp.optimoleDashMetrics, target: '_blank' };
252+
case 'offloaded_images':
253+
return { onClick: () => navigate( settingsTab.offload_image ) };
254+
}
255+
};
256+
207257
return (
208258
<div className="grid gap-5">
209259
<div className="bg-white p-8 border-0 rounded-lg shadow-md">
@@ -285,9 +335,11 @@ const Dashboard = () => {
285335
</div>
286336

287337
<div className="flex pt-5 gap-5 flex-col md:flex-row">
288-
{ metrics.map( metric => {
338+
{ availableMetrics.map( metric => {
289339
const rawValue = userData[ metric.value ];
290340
const { formattedValue, unit } = formatMetric( metric.value, rawValue );
341+
const buttonAction = getMetricButtonAction( metric.value );
342+
const showButton = 'free' !== userData.plan && metric.hasButton;
291343

292344
return (
293345
<div
@@ -297,18 +349,35 @@ const Dashboard = () => {
297349
) }
298350
>
299351
<div className="flex w-full flex-col">
300-
<div className="text-sm text-gray-500">
301-
{ metric.label }
352+
<div className='flex flex-row items-center gap-2 mb-2'>
353+
<Icon icon={ metric.icon } size={ 16 } className="text-info" />
354+
<div className="text-sm text-gray-500">
355+
{ metric.label }
356+
</div>
302357
</div>
303358

304359
<div className='flex items-end gap-1'>
305360
<span className='text-2xl text-black font-bold'>{formattedValue}</span>
306361
<span className='text-sm text-gray-500'>{unit}</span>
307362
</div>
308363

309-
<div className="font-normal text-gray-600">
364+
<div className={ `font-normal text-gray-600 ${ showButton ? 'mb-3' : '' }` }>
310365
{ metric.description }
311366
</div>
367+
368+
{ showButton && (
369+
<Button
370+
variant="secondary"
371+
size="small"
372+
className="mt-auto font-semibold rounded-md w-fit px-3 flex items-center gap-1"
373+
{ ...buttonAction }
374+
>
375+
{ metric.buttonText }
376+
{ ( 'traffic' === metric.value ) && (
377+
<Icon icon={ external } size={ 16 } />
378+
) }
379+
</Button>
380+
) }
312381
</div>
313382
</div>
314383
);

assets/src/dashboard/utils/icons.js

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/src/global.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ export interface UserData {
577577
is_cname_assigned: string
578578
extra_visits: boolean
579579
renews_on: number
580+
can_use_offloading: boolean
580581
}
581582

582583
export interface AvailableApp2 {

inc/admin.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,7 @@ private function localize_dashboard_app() {
13821382
'optimoleHome' => tsdk_translate_link( 'https://optimole.com/' ),
13831383
'optimoleDashHome' => tsdk_translate_link( 'https://dashboard.optimole.com/', 'query' ),
13841384
'optimoleDashBilling' => tsdk_translate_link( 'https://dashboard.optimole.com/settings/billing', 'query' ),
1385+
'optimoleDashMetrics' => tsdk_translate_link( tsdk_utmify( 'https://dashboard.optimole.com/metrics', 'wp-plugin', 'shortcut' ) ),
13851386
'offload_upgrade_url' => tsdk_translate_link( tsdk_utmify( 'https://optimole.com/pricing/', 'offload' ) ),
13861387
'days_since_install' => round( ( time() - get_option( 'optimole_wp_install', 0 ) ) / DAY_IN_SECONDS ),
13871388
'is_offload_media_available' => $is_offload_media_available,
@@ -1748,6 +1749,15 @@ private function get_dashboard_strings() {
17481749
'metricsSubtitle3' => __( 'Average Reduction', 'optimole-wp' ),
17491750
'metricsTitle4' => __( 'CDN Traffic', 'optimole-wp' ),
17501751
'metricsSubtitle4' => __( 'This month', 'optimole-wp' ),
1752+
'metricsTitle5' => __( 'Offloaded images', 'optimole-wp' ),
1753+
'metricsSubtitle5' => __( 'Offloaded to cloud', 'optimole-wp' ),
1754+
// translators: is used as singular when the number of images is 1 for a unit label.
1755+
'image' => __( 'image', 'optimole-wp' ),
1756+
// translators: is used as plural when the number of images is more than 1 for a unit label.
1757+
'images' => __( 'images', 'optimole-wp' ),
1758+
'view_analytics' => __( 'View Analytics', 'optimole-wp' ),
1759+
'adjust_compression' => __( 'Adjust Compression', 'optimole-wp' ),
1760+
'manage_offloading' => __( 'Manage image offloading', 'optimole-wp' ),
17511761
],
17521762
'quick_actions' => [
17531763
'speed_test_title' => __( 'Test Your Site Speed', 'optimole-wp' ),

inc/v2/Offload/Loader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function __construct() {
2525
* Adds filters to integrate the custom image editor into WordPress.
2626
*/
2727
public function register_hooks() {
28-
if( has_filter( 'wp_image_editors', 'photon_subsizes_override_image_editors' )){
28+
if ( has_filter( 'wp_image_editors', 'photon_subsizes_override_image_editors' ) ) {
2929
return;
3030
}
3131
add_filter( 'wp_image_editors', [ $this, 'register_image_editor' ] );

0 commit comments

Comments
 (0)