Skip to content

Commit 3bc4f87

Browse files
authored
Merge pull request #513 from ProgressPlanner/ari/excess-points-complete-previous-monthly-badge
Allow excess points to complete previous monthly badge
2 parents bf48f2c + dff55d1 commit 3bc4f87

17 files changed

Lines changed: 367 additions & 35 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
= 1.6.0 =
22

3+
Enhancements:
4+
5+
* Allow users to collect extra points for previous months' badges.
6+
37
Under the hood:
48

59
* Ravi's Recommendations are now a custom post type.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/* global customElements, HTMLElement */
2+
/*
3+
* Badge Progress Bar
4+
*
5+
* A web component to display a badge progress bar.
6+
*
7+
* Dependencies: progress-planner/l10n, progress-planner/web-components/prpl-badge
8+
*/
9+
10+
/**
11+
* Register the custom web component.
12+
*/
13+
customElements.define(
14+
'prpl-badge-progress-bar',
15+
class extends HTMLElement {
16+
constructor( badgeId, points, maxPoints ) {
17+
// Get parent class properties
18+
super();
19+
badgeId = badgeId || this.getAttribute( 'data-badge-id' );
20+
points = points || this.getAttribute( 'data-points' );
21+
maxPoints = maxPoints || this.getAttribute( 'data-max-points' );
22+
const progress = ( points / maxPoints ) * 100;
23+
24+
this.innerHTML = `
25+
<div class="prpl-badge-progress-bar-container" style="padding: 1rem 0;">
26+
<div
27+
class="prpl-badge-progress-bar"
28+
style="
29+
width: 100%;
30+
height: 1rem;
31+
background-color: var(--prpl-color-gray-1);
32+
border-radius: 0.5rem;
33+
position: relative;"
34+
>
35+
<div
36+
class="prpl-badge-progress-bar-progress"
37+
style="
38+
width: ${ progress }%;
39+
height: 100%;
40+
background-color: var(--prpl-color-accent-orange);
41+
border-radius: 0.5rem;"
42+
></div>
43+
<prpl-badge
44+
badge-id="${ badgeId }"
45+
style="
46+
display:flex;
47+
width: 5rem;
48+
height: 5rem;
49+
position: absolute;
50+
left: calc(${ progress }% - 2.5rem);
51+
top: -2.5rem;"
52+
></prpl-badge>
53+
</div>
54+
</div>
55+
`;
56+
}
57+
}
58+
);
59+
60+
/**
61+
* Update the previous month badge progress bar.
62+
*
63+
* @param {number} pointsDiff The points difference.
64+
*
65+
* @return {void}
66+
*/
67+
// eslint-disable-next-line no-unused-vars
68+
const prplUpdatePreviousMonthBadgeProgressBar = ( pointsDiff ) => {
69+
const progressBars = document.querySelectorAll(
70+
'.prpl-previous-month-badge-progress-bar-wrapper prpl-badge-progress-bar'
71+
);
72+
73+
// Bail early if no badge progress bars are found.
74+
if ( ! progressBars.length ) {
75+
return;
76+
}
77+
78+
// Get the 1st incomplete badge progress bar.
79+
const progressBar =
80+
parseInt( progressBars[ 0 ]?.getAttribute( 'data-points' ) ) >=
81+
parseInt( progressBars[ 0 ]?.getAttribute( 'data-max-points' ) )
82+
? progressBars[ 1 ]
83+
: progressBars[ 0 ];
84+
85+
// Bail early if no badge progress bar is found.
86+
if ( ! progressBar ) {
87+
return;
88+
}
89+
90+
// Get the badge progress bar properties.
91+
const badgeId = progressBar.getAttribute( 'data-badge-id' );
92+
const badgePoints = progressBar.getAttribute( 'data-points' );
93+
const badgeMaxPoints = progressBar.getAttribute( 'data-max-points' );
94+
const badgeProgress = customElements.get( 'prpl-badge-progress-bar' );
95+
const badgeNewPoints = parseInt( badgePoints ) + pointsDiff;
96+
97+
// Create a new badge progress bar.
98+
const newProgressBar = new badgeProgress(
99+
badgeId,
100+
badgeNewPoints,
101+
badgeMaxPoints
102+
);
103+
newProgressBar.setAttribute( 'data-badge-id', badgeId );
104+
newProgressBar.setAttribute( 'data-points', badgeNewPoints );
105+
newProgressBar.setAttribute( 'data-max-points', badgeMaxPoints );
106+
107+
// Replace the old badge progress bar with the new one.
108+
progressBar.replaceWith( newProgressBar );
109+
110+
// Update the remaining points.
111+
const remainingPointsEl = document.querySelector(
112+
`.prpl-previous-month-badge-progress-bar-wrapper[data-badge-id="${ badgeId }"] .prpl-previous-month-badge-progress-bar-remaining`
113+
);
114+
115+
if ( remainingPointsEl ) {
116+
remainingPointsEl.textContent = remainingPointsEl.textContent.replace(
117+
remainingPointsEl.getAttribute( 'data-remaining' ),
118+
badgeMaxPoints - badgeNewPoints
119+
);
120+
remainingPointsEl.setAttribute(
121+
'data-remaining',
122+
badgeMaxPoints - badgeNewPoints
123+
);
124+
}
125+
126+
// Update the previous month badge points number.
127+
const badgePointsNumberEl = document.querySelector(
128+
`.prpl-previous-month-badge-progress-bar-wrapper[data-badge-id="${ badgeId }"] .prpl-widget-previous-ravi-points-number`
129+
);
130+
if ( badgePointsNumberEl ) {
131+
badgePointsNumberEl.textContent = badgeNewPoints + 'pt';
132+
}
133+
134+
// If the previous month badge is completed, update badge elements.
135+
if ( badgeNewPoints >= parseInt( badgeMaxPoints ) ) {
136+
document
137+
.querySelectorAll(
138+
`.prpl-badge-row-wrapper-inner .prpl-badge prpl-badge[complete="false"][badge-id="${ badgeId }"]`
139+
)
140+
?.forEach( ( badge ) => {
141+
badge.setAttribute( 'complete', 'true' );
142+
} );
143+
144+
// Remove the previous month badge progress bar.
145+
document
146+
.querySelector(
147+
`.prpl-previous-month-badge-progress-bar-wrapper[data-badge-id="${ badgeId }"]`
148+
)
149+
?.remove();
150+
151+
// If there are no more progress bars, remove the previous month badge progress bar wrapper.
152+
if (
153+
! document.querySelector(
154+
'.prpl-previous-month-badge-progress-bar-wrapper'
155+
)
156+
) {
157+
document
158+
.querySelector(
159+
'.prpl-previous-month-badge-progress-bars-wrapper'
160+
)
161+
?.remove();
162+
}
163+
}
164+
};

assets/js/web-components/prpl-gauge.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
/* global customElements, HTMLElement */
1+
/* global customElements, HTMLElement, prplUpdatePreviousMonthBadgeProgressBar */
22
/*
33
* Web Component: prpl-gauge
44
*
55
* A web component that displays a gauge.
66
*
7-
* Dependencies: progress-planner/web-components/prpl-badge
7+
* Dependencies: progress-planner/web-components/prpl-badge, progress-planner/web-components/prpl-badge-progress-bar
88
*/
99

1010
/**
@@ -174,16 +174,16 @@ const prplUpdateRaviGauge = ( pointsDiff ) => {
174174
// Mark badge as completed, in the a Monthly badges widgets, if we reached the max points.
175175
if ( newValue >= parseInt( gaugeProps.max ) ) {
176176
// We have multiple badges, one in widget and the other in the popover.
177-
const badges = document.querySelectorAll(
178-
'.prpl-badge-row-wrapper-inner .prpl-badge prpl-badge[complete="false"][badge-id="' +
179-
gaugeProps.badgeId +
180-
'"]'
181-
);
182-
183-
if ( badges ) {
184-
badges.forEach( ( badge ) => {
177+
document
178+
.querySelectorAll(
179+
`.prpl-badge-row-wrapper-inner .prpl-badge prpl-badge[complete="false"][badge-id="${ gaugeProps.badgeId }"]`
180+
)
181+
?.forEach( ( badge ) => {
185182
badge.setAttribute( 'complete', 'true' );
186183
} );
184+
185+
if ( gaugeProps.value >= parseInt( gaugeProps.max ) ) {
186+
prplUpdatePreviousMonthBadgeProgressBar( pointsDiff );
187187
}
188188
}
189189
};

classes/admin/class-page.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ public function enqueue_scripts() {
172172

173173
if ( true === \progress_planner()->is_privacy_policy_accepted() ) {
174174
\progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-gauge' );
175+
\progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-badge-progress-bar' );
175176
\progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-chart-bar' );
176177
\progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-chart-line' );
177178
\progress_planner()->get_admin__enqueue()->enqueue_script( 'web-components/prpl-big-counter' );

classes/admin/widgets/class-suggested-tasks.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Progress_Planner\Admin\Widgets;
99

10+
use DateTime;
1011
use Progress_Planner\Badges\Monthly;
1112

1213
/**
@@ -24,7 +25,7 @@ final class Suggested_Tasks extends Widget {
2425
/**
2526
* Get the score.
2627
*
27-
* @return int The score.
28+
* @return array<string, int> The scores.
2829
*/
2930
public function get_score() {
3031
$activities = \progress_planner()->get_activities__query()->query_activities(
@@ -40,7 +41,34 @@ public function get_score() {
4041
$score += $activity->get_points( $activity->date );
4142
}
4243

43-
return (int) min( Monthly::TARGET_POINTS, max( 0, floor( $score ) ) );
44+
return [
45+
'score' => (int) $score,
46+
'target' => (int) Monthly::TARGET_POINTS,
47+
'target_score' => (int) min( Monthly::TARGET_POINTS, max( 0, floor( $score ) ) ),
48+
];
49+
}
50+
51+
/**
52+
* Get previous month badge.
53+
*
54+
* @return \Progress_Planner\Badges\Monthly[]
55+
*/
56+
public function get_previous_incomplete_months_badges() {
57+
$previous_incomplete_month_badges = [];
58+
59+
$minus_one_month = ( new DateTime() )->modify( 'first day of previous month' );
60+
$minus_one_month_badge = Monthly::get_instance_from_id( Monthly::get_badge_id_from_date( $minus_one_month ) );
61+
if ( $minus_one_month_badge && $minus_one_month_badge->progress_callback()['progress'] < 100 ) {
62+
$previous_incomplete_month_badges[] = $minus_one_month_badge;
63+
}
64+
65+
$minus_two_months = ( new DateTime() )->modify( 'first day of previous month' )->modify( 'first day of previous month' );
66+
$minus_two_months_badge = Monthly::get_instance_from_id( Monthly::get_badge_id_from_date( $minus_two_months ) );
67+
if ( $minus_two_months_badge && $minus_two_months_badge->progress_callback()['progress'] < 100 ) {
68+
$previous_incomplete_month_badges[] = $minus_two_months_badge;
69+
}
70+
71+
return $previous_incomplete_month_badges;
4472
}
4573

4674
/**
@@ -49,6 +77,8 @@ public function get_score() {
4977
* @return void
5078
*/
5179
public function enqueue_scripts() {
80+
parent::enqueue_scripts();
81+
5282
// Enqueue the badge scroller script.
5383
\progress_planner()->get_admin__enqueue()->enqueue_script(
5484
'widgets/suggested-tasks-badge-scroller',

classes/badges/class-badge.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@ abstract public function get_description();
5959
/**
6060
* Progress callback.
6161
*
62+
* @param array $args The arguments for the progress callback.
63+
*
6264
* @return array
6365
*/
64-
abstract public function progress_callback();
66+
abstract public function progress_callback( $args = [] );
6567

6668
/**
6769
* Get the saved progress.

0 commit comments

Comments
 (0)