Skip to content

Commit b43ae87

Browse files
authored
Merge pull request #901 from Codeinwp/feat/opml-service/1361
feat: redesign the metrics layout
2 parents dd0f213 + 9854a97 commit b43ae87

File tree

4 files changed

+207
-98
lines changed

4 files changed

+207
-98
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const LastImages = () => {
135135
};
136136

137137
return (
138-
<div className="hidden lg:block pt-5 border-grayish-blue border-0 border-t-2 border-solid">
138+
<div className="hidden lg:block pt-5">
139139
<h3 className="text-base m-0">{ optimoleDashboardApp.strings.latest_images.last } { optimoleDashboardApp.strings.latest_images.optimized_images }</h3>
140140

141141
{ ( isInitialLoading && ! isLoaded ) && (

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

Lines changed: 157 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ import {
1313

1414
import { useSelect } from '@wordpress/data';
1515

16+
import { clearCache } from '../../../utils/api';
17+
1618
/**
1719
* Internal dependencies.
1820
*/
1921
import {
20-
imagesNumber,
21-
savedSize,
22-
compressionPercentage,
23-
traffic,
24-
quota,
25-
warning
22+
bolt,
23+
update,
24+
offloadImage,
25+
settings
2626
} from '../../../utils/icons';
2727

2828
import ProgressBar from '../../components/ProgressBar';
@@ -33,29 +33,67 @@ import LastImages from './LastImages';
3333
const cardClasses = 'flex p-6 bg-light-blue border border-blue-300 rounded-md';
3434

3535
const metrics = [
36-
{
37-
label: optimoleDashboardApp.strings.metrics.metricsTitle1,
38-
description: optimoleDashboardApp.strings.metrics.metricsSubtitle1,
39-
value: 'images_number',
40-
icon: imagesNumber
41-
},
4236
{
4337
label: optimoleDashboardApp.strings.metrics.metricsTitle2,
4438
description: optimoleDashboardApp.strings.metrics.metricsSubtitle2,
45-
value: 'saved_size',
46-
icon: savedSize
39+
value: 'saved_size'
4740
},
4841
{
4942
label: optimoleDashboardApp.strings.metrics.metricsTitle3,
5043
description: optimoleDashboardApp.strings.metrics.metricsSubtitle3,
51-
value: 'compression_percentage',
52-
icon: compressionPercentage
44+
value: 'compression_percentage'
5345
},
5446
{
5547
label: optimoleDashboardApp.strings.metrics.metricsTitle4,
5648
description: optimoleDashboardApp.strings.metrics.metricsSubtitle4,
57-
value: 'traffic',
58-
icon: traffic
49+
value: 'traffic'
50+
}
51+
];
52+
53+
const settingsTab = {
54+
offload_image: 1,
55+
advance: 2
56+
};
57+
58+
const navigate = ( tabId ) => {
59+
const links = window.optimoleDashboardApp.submenu_links;
60+
const settingsLink = links.find( link => '#settings' === link.hash );
61+
if ( settingsLink ) {
62+
const existingLink = document.querySelector( `a[href="${settingsLink.href}"]` );
63+
existingLink.click();
64+
setTimeout( () => {
65+
const tabItems = document.querySelectorAll( '.optml-settings ul li' );
66+
tabItems[tabId]?.querySelector( 'button' ).click();
67+
window.scrollTo( 0, 0 );
68+
}, 500 );
69+
}
70+
};
71+
72+
const quickactions = [
73+
{
74+
icon: <Icon icon={bolt} className="text-info"/>,
75+
title: optimoleDashboardApp.strings.quick_actions.speed_test_title,
76+
description: optimoleDashboardApp.strings.quick_actions.speed_test_desc,
77+
link: optimoleDashboardApp.strings.quick_actions.speed_test_link,
78+
value: 'speedTest'
79+
},
80+
{
81+
icon: <Icon icon={update} className="text-info"/>,
82+
title: optimoleDashboardApp.strings.quick_actions.clear_cache_images,
83+
description: optimoleDashboardApp.strings.quick_actions.clear_cache,
84+
value: clearCache
85+
},
86+
{
87+
icon: <Icon icon={offloadImage} className="text-info" />,
88+
title: optimoleDashboardApp.strings.quick_actions.offload_images,
89+
description: optimoleDashboardApp.strings.quick_actions.offload_images_desc,
90+
value: () => navigate( settingsTab.offload_image )
91+
},
92+
{
93+
icon: <Icon icon={settings} className="text-info"/>,
94+
title: optimoleDashboardApp.strings.quick_actions.advance_settings,
95+
description: optimoleDashboardApp.strings.quick_actions.configure_settings,
96+
value: () => navigate( settingsTab.advance )
5997
}
6098
];
6199

@@ -109,97 +147,126 @@ const Dashboard = () => {
109147
Math.floor( Math.random() * 40 ) + 10;
110148
}
111149

112-
// Format based on metric type
113-
if ( 'saved_size' === metric ) {
114-
return ( metricValue / 1000 ).toFixed( 2 ) + 'MB';
115-
}
116-
117-
if ( 'compression_percentage' === metric ) {
118-
return metricValue.toFixed( 2 ) + '%';
119-
}
120-
121-
if ( 'traffic' === metric ) {
122-
return metricValue.toFixed( 2 ) + 'MB';
123-
}
124-
125150
return metricValue;
126151
};
127152

128-
return (
129-
<div className="bg-white p-8 border-0 rounded-lg shadow-md">
130-
{ ( 0 < optimoleDashboardApp.strings.notice_just_activated.length && 'active' === userStatus ) && <ActivatedNotice/> }
153+
const formatMetricValue = metric => {
154+
const value = getFormattedMetric( metric );
155+
const calcValue = 'saved_size' === metric ? ( value / 1000 ).toFixed( 2 ) : value.toFixed( 2 );
156+
return (
157+
<div className='flex items-end gap-1'>
158+
<span className='text-2xl text-black font-bold'>{calcValue}</span>
159+
<span className='text-sm text-gray-500'>{ 'compression_percentage' === metric ? '%' : 'MB' }</span>
160+
</div>
161+
);
162+
};
131163

132-
{ 'inactive' === userStatus && <InactiveWarning/> }
164+
return (
165+
<>
166+
<div className="bg-white p-8 border-0 rounded-lg shadow-md">
167+
{ ( 0 < optimoleDashboardApp.strings.notice_just_activated.length && 'active' === userStatus ) && <ActivatedNotice/> }
133168

134-
<div
135-
className={ classNames(
136-
cardClasses,
137-
'gap-8 flex-col sm:flex-row items-start sm:items-center'
138-
) }
139-
>
140-
<Icon icon={ quota } />
169+
{ 'inactive' === userStatus && <InactiveWarning/> }
141170

142-
<div className="flex w-full flex-col">
143-
<div className="flex w-full justify-between">
171+
<div className='py-6 gap-6 flex-col sm:flex-row items-start sm:items-center'>
172+
<div className='flex w-full justify-between sm:items-center'>
144173
<div className="text-gray-800 text-2xl font-bold">
145-
{ userData.visitors_pretty } / { userData.visitors_limit_pretty }
146-
147-
<span className="text-gray-600 text-base font-normal ml-2">
174+
{ optimoleDashboardApp.strings.dashboard_title }
175+
</div>
176+
<div className="flex items-center gap-2">
177+
<div className="text-gray-600 text-base font-normal ml-2">
148178
{ optimoleDashboardApp.strings.quota }
149-
</span>
179+
<span className="pl-2 text-gray-800 font-bold">
180+
{ userData.visitors_pretty } / { userData.visitors_limit_pretty }
181+
</span>
182+
</div>
183+
<div className='w-20'>
184+
<ProgressBar
185+
value={ userData.visitors }
186+
max={ userData.visitors_limit }
187+
/>
188+
</div>
189+
<span>{ visitorsLimitPercent }%</span>
150190
</div>
151-
152-
{ ( 70 > visitorsLimitPercent ) && (
153-
<Button
154-
variant="default"
155-
className="optml__button rounded font-bold min-h-40"
156-
href={ optimoleDashboardApp.optimoleDashBilling }
157-
target="_blank"
158-
>
159-
{ optimoleDashboardApp.strings.upgrade.title }
160-
</Button>
161-
) }
162191
</div>
192+
</div>
163193

194+
<div
195+
className={ classNames(
196+
cardClasses,
197+
'gap-8 flex-col sm:flex-row items-start sm:items-center'
198+
) }
199+
>
164200
<div>
165-
<ProgressBar
166-
className="mt-2.5 mb-3 mx-0"
167-
value={ userData.visitors }
168-
max={ userData.visitors_limit }
169-
/>
201+
<div className="text-gray-800 text-xl font-bold">
202+
{ optimoleDashboardApp.strings.banner_title }
203+
</div>
204+
<div className="text-gray-600 text-base">
205+
{ optimoleDashboardApp.strings.banner_description }
206+
</div>
207+
</div>
208+
</div>
209+
210+
<div className="flex py-5 gap-5 flex-col md:flex-row">
211+
{ metrics.map( metric => {
212+
return (
213+
<div
214+
key={ metric.value }
215+
className={ classNames(
216+
'p-3 basis-1/3 flex-col items-start border rounded-md border-solid bg-white border-light-gray border-slate-400'
217+
) }
218+
>
219+
<div className="flex w-full flex-col">
220+
<div className="not-italic font-normal text-sm text-gray-500">
221+
{ metric.label }
222+
</div>
223+
224+
<div>
225+
{ formatMetricValue( metric.value ) }
226+
</div>
170227

228+
<div className="font-normal text-sm text-gray-600">
229+
{ metric.description }
230+
</div>
231+
</div>
232+
</div>
233+
);
234+
}) }
235+
</div>
236+
</div>
237+
<div className="my-3 bg-white p-8 border-0 rounded-lg shadow-md">
238+
<div className="text-gray-800 font-bold text-2xl">{ optimoleDashboardApp.strings.quick_action_title }</div>
239+
<div className="grid grid-cols-1 md:grid-cols-2 gap-5 py-5">
240+
{quickactions.map( ( action, index ) => (
171241
<div
172-
className="optml__tooltip"
173-
style={ {
174-
left: visitorsLimitPercent + '%',
175-
marginLeft: 15 > visitorsLimitPercent ? '-15px' : '-20px',
176-
display: 100 < visitorsLimitPercent ? 'none' : 'block'
177-
} }
242+
key={index}
243+
className="flex items-start items-center gap-3 p-4 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors"
178244
>
179-
<span>{ visitorsLimitPercent }%</span>
245+
{action.icon}
246+
<div className="flex flex-col">
247+
<span className="font-medium text-base text-gray-800">{action.title}</span>
248+
{ 'speedTest' === action.value ? (
249+
<a href={action.link} target="_blank" className="text-info text-sm font-medium hover:text-info">{action.description}</a>
250+
) : (
251+
<Button
252+
variant="default"
253+
className="text-info text-sm font-medium p-0 h-5 focus:!shadow-none focus:!outline-none"
254+
onClick={ () => action.value() }
255+
>
256+
{ action.description }
257+
</Button>
258+
) }
259+
</div>
180260
</div>
181-
</div>
261+
) )}
182262
</div>
183263
</div>
184-
185-
<div className="flex py-5 gap-5 flex-col md:flex-row">
186-
{ metrics.map( metric => {
187-
return (
188-
<DashboardMetricBox
189-
key={ metric.value }
190-
value={ getFormattedMetric( metric.value ) }
191-
label={ metric.label }
192-
description={ metric.description }
193-
icon={ metric.icon }
194-
/>
195-
);
196-
})}
264+
<div className="bg-white p-8 border-0 rounded-lg shadow-md">
265+
{ 'yes' !== optimoleDashboardApp.remove_latest_images && (
266+
<LastImages />
267+
) }
197268
</div>
198-
199-
{ 'yes' !== optimoleDashboardApp.remove_latest_images && (
200-
<LastImages />
201-
) }
202-
</div>
269+
</>
203270
);
204271
};
205272

assets/src/dashboard/utils/icons.js

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

inc/admin.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,10 @@ private function get_dashboard_strings() {
15001500
'privacy_menu' => __( 'Privacy', 'optimole-wp' ),
15011501
'testdrive_menu' => __( 'Test Optimole', 'optimole-wp' ),
15021502
'service_details' => __( 'Image optimization service', 'optimole-wp' ),
1503+
'dashboard_title' => __( 'Image Optimization Overview', 'optimole-wp' ),
1504+
'banner_title' => __( 'All images are automatically optimized!', 'optimole-wp' ),
1505+
'banner_description' => __( 'Optimole is handling all your images in real-time with our CloudFront CDN (450+ locations worldwide)', 'optimole-wp' ),
1506+
'quick_action_title' => __( 'Quick Actions' ),
15031507
'connect_btn' => __( 'Connect to Optimole', 'optimole-wp' ),
15041508
'disconnect_btn' => __( 'Disconnect', 'optimole-wp' ),
15051509
'select' => __( 'Select', 'optimole-wp' ),
@@ -1551,7 +1555,7 @@ private function get_dashboard_strings() {
15511555
'connecting' => __( 'CONNECTING', 'optimole-wp' ),
15521556
'not_connected' => __( 'NOT CONNECTED', 'optimole-wp' ),
15531557
'usage' => __( 'Monthly Usage', 'optimole-wp' ),
1554-
'quota' => __( 'Monthly visits quota', 'optimole-wp' ),
1558+
'quota' => __( 'Monthly visits:', 'optimole-wp' ),
15551559
'logged_in_as' => __( 'LOGGED IN AS', 'optimole-wp' ),
15561560
'private_cdn_url' => __( 'IMAGES DOMAIN', 'optimole-wp' ),
15571561
'existing_user' => __( 'Existing user?', 'optimole-wp' ),
@@ -1669,12 +1673,23 @@ private function get_dashboard_strings() {
16691673
'metrics' => [
16701674
'metricsTitle1' => __( 'Images optimized', 'optimole-wp' ),
16711675
'metricsSubtitle1' => __( 'Since plugin activation', 'optimole-wp' ),
1672-
'metricsTitle2' => __( 'Saved file size', 'optimole-wp' ),
1673-
'metricsSubtitle2' => __( 'For the latest 10 images', 'optimole-wp' ),
1674-
'metricsTitle3' => __( 'Average compression', 'optimole-wp' ),
1675-
'metricsSubtitle3' => __( 'During last month', 'optimole-wp' ),
1676-
'metricsTitle4' => __( 'Traffic', 'optimole-wp' ),
1677-
'metricsSubtitle4' => __( 'During last month', 'optimole-wp' ),
1676+
'metricsTitle2' => __( 'Saved File Size', 'optimole-wp' ),
1677+
'metricsSubtitle2' => __( 'Latest 10 images', 'optimole-wp' ),
1678+
'metricsTitle3' => __( 'Average Compression', 'optimole-wp' ),
1679+
'metricsSubtitle3' => __( 'Average Reduction', 'optimole-wp' ),
1680+
'metricsTitle4' => __( 'CDN Traffic', 'optimole-wp' ),
1681+
'metricsSubtitle4' => __( 'This month', 'optimole-wp' ),
1682+
],
1683+
'quick_actions' => [
1684+
'speed_test_title' => __( 'Test Your Site Speed', 'optimole-wp' ),
1685+
'speed_test_desc' => __( 'Run speed test', 'optimole-wp' ),
1686+
'speed_test_link' => add_query_arg( 'url', get_site_url(), 'https://pagespeed.web.dev/analysis' ),
1687+
'clear_cache_images' => __( 'Clear Cached Images', 'optimole-wp' ),
1688+
'clear_cache' => __( 'Clear cache', 'optimole-wp' ),
1689+
'offload_images' => __( 'Enable Offload Images', 'optimole-wp' ),
1690+
'offload_images_desc' => __( 'Free up space on your server', 'optimole-wp' ),
1691+
'advance_settings' => __( 'Advanced Settings', 'optimole-wp' ),
1692+
'configure_settings' => __( 'Configure settings', 'optimole-wp' ),
16781693
],
16791694
'options_strings' => [
16801695
'best_format_title' => __( 'Automatic Best Image Format Selection', 'optimole-wp' ),

0 commit comments

Comments
 (0)