@dgpholdings/greatoak-shared 1.2.20 → 1.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/TApiExercise.d.ts +2 -0
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +1 -3
- package/dist/utils/scoring/calculateQualityScore.d.ts +4 -3
- package/dist/utils/scoring/calculateQualityScore.js +16 -14
- package/dist/utils/scoring/constants.d.ts +3 -3
- package/dist/utils/scoring/constants.js +3 -3
- package/package.json +1 -1
|
@@ -119,6 +119,8 @@ export type TExercise = {
|
|
|
119
119
|
thumbnailBlurHash?: string;
|
|
120
120
|
instructionsHtml: string;
|
|
121
121
|
importantTipsHtml: string;
|
|
122
|
+
popularityIndex: number;
|
|
123
|
+
isFavorite?: boolean;
|
|
122
124
|
};
|
|
123
125
|
export type TBodyPartExercises = Record<TBodyPart, TExercise[]>;
|
|
124
126
|
export type TApiCreateOrUpdateExerciseReq = {
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { toNumber } from "./number.util";
|
|
2
2
|
export { mmssToSecs, isUserAllowedToUpdate, getDaysAndHoursDifference, } from "./time.util";
|
|
3
3
|
export { countryToCurrencyCode } from "./billing.utils";
|
|
4
|
-
export { calculateExerciseScore } from "./scoring.utils";
|
|
5
4
|
export { isDefined, isDefinedNumber } from "./isDefined.utils";
|
|
6
5
|
export { slugifyText } from "./slugify.util";
|
|
7
6
|
export { toError } from "./toError.util";
|
package/dist/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.calculateTotalVolume = exports.calculateExerciseScoreV2 = exports.NOOP = exports.isEmail = exports.isAnonymousEmail = exports.maskEmail = exports.generatePlanCode = exports.toError = exports.slugifyText = exports.isDefinedNumber = exports.isDefined = exports.
|
|
3
|
+
exports.calculateTotalVolume = exports.calculateExerciseScoreV2 = exports.NOOP = exports.isEmail = exports.isAnonymousEmail = exports.maskEmail = exports.generatePlanCode = exports.toError = exports.slugifyText = exports.isDefinedNumber = exports.isDefined = exports.countryToCurrencyCode = exports.getDaysAndHoursDifference = exports.isUserAllowedToUpdate = exports.mmssToSecs = exports.toNumber = void 0;
|
|
4
4
|
var number_util_1 = require("./number.util");
|
|
5
5
|
Object.defineProperty(exports, "toNumber", { enumerable: true, get: function () { return number_util_1.toNumber; } });
|
|
6
6
|
var time_util_1 = require("./time.util");
|
|
@@ -9,8 +9,6 @@ Object.defineProperty(exports, "isUserAllowedToUpdate", { enumerable: true, get:
|
|
|
9
9
|
Object.defineProperty(exports, "getDaysAndHoursDifference", { enumerable: true, get: function () { return time_util_1.getDaysAndHoursDifference; } });
|
|
10
10
|
var billing_utils_1 = require("./billing.utils");
|
|
11
11
|
Object.defineProperty(exports, "countryToCurrencyCode", { enumerable: true, get: function () { return billing_utils_1.countryToCurrencyCode; } });
|
|
12
|
-
var scoring_utils_1 = require("./scoring.utils");
|
|
13
|
-
Object.defineProperty(exports, "calculateExerciseScore", { enumerable: true, get: function () { return scoring_utils_1.calculateExerciseScore; } });
|
|
14
12
|
var isDefined_utils_1 = require("./isDefined.utils");
|
|
15
13
|
Object.defineProperty(exports, "isDefined", { enumerable: true, get: function () { return isDefined_utils_1.isDefined; } });
|
|
16
14
|
Object.defineProperty(exports, "isDefinedNumber", { enumerable: true, get: function () { return isDefined_utils_1.isDefinedNumber; } });
|
|
@@ -55,14 +55,15 @@ interface IRawRecord {
|
|
|
55
55
|
* @param parsedSets Cleaned sets (from parseRecords) — only completed sets
|
|
56
56
|
* @param rawRecords Original TRecord[] — needed for completion count (includes skipped)
|
|
57
57
|
* @param timingGuardrails Exercise's guardrails — for rest period validation
|
|
58
|
+
* @param isStrictTimingModeScoring If false, ignores the rest discipline penalty.
|
|
58
59
|
* @returns { score: 0–100, breakdown: { completion, consistency, effortAdequacy, restDiscipline } }
|
|
59
60
|
*
|
|
60
61
|
* @example
|
|
61
|
-
* const { score, breakdown } = calculateQualityScore(parsed, raw, guardrails);
|
|
62
|
+
* const { score, breakdown } = calculateQualityScore(parsed, raw, guardrails, false);
|
|
62
63
|
* // score: 81
|
|
63
|
-
* // breakdown: { completion: 100, consistency: 75, effortAdequacy: 80, restDiscipline:
|
|
64
|
+
* // breakdown: { completion: 100, consistency: 75, effortAdequacy: 80, restDiscipline: 65 }
|
|
64
65
|
*/
|
|
65
|
-
export declare function calculateQualityScore(parsedSets: IParsedSet[], rawRecords: IRawRecord[], timingGuardrails?: ITimingGuardrails): {
|
|
66
|
+
export declare function calculateQualityScore(parsedSets: IParsedSet[], rawRecords: IRawRecord[], timingGuardrails?: ITimingGuardrails, isStrictTimingModeScoring?: boolean): {
|
|
66
67
|
score: number;
|
|
67
68
|
breakdown: IQualityBreakdown;
|
|
68
69
|
};
|
|
@@ -13,14 +13,15 @@ const helpers_1 = require("./helpers");
|
|
|
13
13
|
* @param parsedSets Cleaned sets (from parseRecords) — only completed sets
|
|
14
14
|
* @param rawRecords Original TRecord[] — needed for completion count (includes skipped)
|
|
15
15
|
* @param timingGuardrails Exercise's guardrails — for rest period validation
|
|
16
|
+
* @param isStrictTimingModeScoring If false, ignores the rest discipline penalty.
|
|
16
17
|
* @returns { score: 0–100, breakdown: { completion, consistency, effortAdequacy, restDiscipline } }
|
|
17
18
|
*
|
|
18
19
|
* @example
|
|
19
|
-
* const { score, breakdown } = calculateQualityScore(parsed, raw, guardrails);
|
|
20
|
+
* const { score, breakdown } = calculateQualityScore(parsed, raw, guardrails, false);
|
|
20
21
|
* // score: 81
|
|
21
|
-
* // breakdown: { completion: 100, consistency: 75, effortAdequacy: 80, restDiscipline:
|
|
22
|
+
* // breakdown: { completion: 100, consistency: 75, effortAdequacy: 80, restDiscipline: 65 }
|
|
22
23
|
*/
|
|
23
|
-
function calculateQualityScore(parsedSets, rawRecords, timingGuardrails) {
|
|
24
|
+
function calculateQualityScore(parsedSets, rawRecords, timingGuardrails, isStrictTimingModeScoring = false) {
|
|
24
25
|
// Edge case: no records at all
|
|
25
26
|
if (rawRecords.length === 0) {
|
|
26
27
|
return {
|
|
@@ -50,7 +51,7 @@ function calculateQualityScore(parsedSets, rawRecords, timingGuardrails) {
|
|
|
50
51
|
const completion = calculateCompletion(parsedSets, rawRecords);
|
|
51
52
|
const consistency = calculateConsistency(parsedSets);
|
|
52
53
|
const effortAdequacy = calculateEffortAdequacy(rawRecords);
|
|
53
|
-
const restDiscipline = calculateRestDiscipline(parsedSets, timingGuardrails);
|
|
54
|
+
const restDiscipline = isStrictTimingModeScoring ? calculateRestDiscipline(parsedSets, timingGuardrails) : constants_1.REST_NO_DATA_SCORE; // 65 by default if not strict
|
|
54
55
|
const score = Math.round(completion * constants_1.QUALITY_WEIGHTS.completion +
|
|
55
56
|
consistency * constants_1.QUALITY_WEIGHTS.consistency +
|
|
56
57
|
effortAdequacy * constants_1.QUALITY_WEIGHTS.effortAdequacy +
|
|
@@ -267,11 +268,11 @@ function scoreAgainstRange(value, range) {
|
|
|
267
268
|
*
|
|
268
269
|
* Uses the exercise's timingGuardrails.restPeriods:
|
|
269
270
|
* optimalRange [min, max] → 100 points
|
|
270
|
-
* within [minimum, maximum] →
|
|
271
|
-
* outside [minimum, maximum] →
|
|
271
|
+
* within [minimum, maximum] → 70–100 (proportional to how close to optimal)
|
|
272
|
+
* outside [minimum, maximum] → 50 points (Reduced penalty so it doesn't tank the score too much)
|
|
272
273
|
*
|
|
273
274
|
* Only scores sets that HAVE rest data (last set often doesn't).
|
|
274
|
-
* If no valid rest data exists at all → neutral
|
|
275
|
+
* If no valid rest data exists at all → neutral 70.
|
|
275
276
|
*
|
|
276
277
|
* The stressRestBonus from timingGuardrails is applied as a final multiplier:
|
|
277
278
|
* exercises where proper rest is especially important (heavy compounds)
|
|
@@ -282,7 +283,7 @@ function calculateRestDiscipline(parsedSets, timingGuardrails) {
|
|
|
282
283
|
// Gather sets that have rest data (non-null)
|
|
283
284
|
const setsWithRest = parsedSets.filter((s) => s.restDurationSecs !== null);
|
|
284
285
|
if (setsWithRest.length === 0)
|
|
285
|
-
return
|
|
286
|
+
return 70; // Increased from REST_NO_DATA_SCORE (which was likely lower)
|
|
286
287
|
// Extract rest period bounds from guardrails
|
|
287
288
|
const restConfig = timingGuardrails === null || timingGuardrails === void 0 ? void 0 : timingGuardrails.restPeriods;
|
|
288
289
|
const optimalMin = (_b = (_a = restConfig === null || restConfig === void 0 ? void 0 : restConfig.optimalRange) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : ((_c = restConfig === null || restConfig === void 0 ? void 0 : restConfig.typical) !== null && _c !== void 0 ? _c : constants_1.FALLBACK_REST_SECS) * 0.75;
|
|
@@ -294,11 +295,12 @@ function calculateRestDiscipline(parsedSets, timingGuardrails) {
|
|
|
294
295
|
const rest = set.restDurationSecs; // Guaranteed non-null by filter
|
|
295
296
|
if (rest >= optimalMin && rest <= optimalMax) {
|
|
296
297
|
// Within optimal range → perfect score
|
|
297
|
-
setScores.push(
|
|
298
|
+
setScores.push(100); // REST_OPTIMAL_SCORE
|
|
298
299
|
}
|
|
299
300
|
else if (rest >= acceptableMin && rest <= acceptableMax) {
|
|
300
301
|
// Within acceptable range but not optimal
|
|
301
|
-
// Score proportionally based on how close to optimal
|
|
302
|
+
// Score proportionally based on how close to optimal, base is 70 now
|
|
303
|
+
const baseAcceptableScore = 70;
|
|
302
304
|
let ratio;
|
|
303
305
|
if (rest < optimalMin) {
|
|
304
306
|
// Between acceptable min and optimal min
|
|
@@ -308,12 +310,12 @@ function calculateRestDiscipline(parsedSets, timingGuardrails) {
|
|
|
308
310
|
// Between optimal max and acceptable max
|
|
309
311
|
ratio = (acceptableMax - rest) / (acceptableMax - optimalMax);
|
|
310
312
|
}
|
|
311
|
-
setScores.push(
|
|
312
|
-
ratio * (
|
|
313
|
+
setScores.push(baseAcceptableScore +
|
|
314
|
+
ratio * (100 - baseAcceptableScore));
|
|
313
315
|
}
|
|
314
316
|
else {
|
|
315
|
-
// Outside even the acceptable range
|
|
316
|
-
setScores.push(
|
|
317
|
+
// Outside even the acceptable range, reduced penalty to 50
|
|
318
|
+
setScores.push(50);
|
|
317
319
|
}
|
|
318
320
|
}
|
|
319
321
|
// Average rest scores
|
|
@@ -184,8 +184,8 @@ export declare const EFFORT_NO_DATA_SCORE = 70;
|
|
|
184
184
|
/** Score when rest is within the optimal range */
|
|
185
185
|
export declare const REST_OPTIMAL_SCORE = 100;
|
|
186
186
|
/** Score when rest is within acceptable (min–max) but not optimal */
|
|
187
|
-
export declare const REST_ACCEPTABLE_BASE =
|
|
187
|
+
export declare const REST_ACCEPTABLE_BASE = 70;
|
|
188
188
|
/** Score when rest is completely outside the acceptable range */
|
|
189
|
-
export declare const REST_OUTSIDE_SCORE =
|
|
189
|
+
export declare const REST_OUTSIDE_SCORE = 50;
|
|
190
190
|
/** Default rest discipline score when no valid rest data exists */
|
|
191
|
-
export declare const REST_NO_DATA_SCORE =
|
|
191
|
+
export declare const REST_NO_DATA_SCORE = 75;
|
|
@@ -220,8 +220,8 @@ exports.EFFORT_NO_DATA_SCORE = 70;
|
|
|
220
220
|
/** Score when rest is within the optimal range */
|
|
221
221
|
exports.REST_OPTIMAL_SCORE = 100;
|
|
222
222
|
/** Score when rest is within acceptable (min–max) but not optimal */
|
|
223
|
-
exports.REST_ACCEPTABLE_BASE =
|
|
223
|
+
exports.REST_ACCEPTABLE_BASE = 70;
|
|
224
224
|
/** Score when rest is completely outside the acceptable range */
|
|
225
|
-
exports.REST_OUTSIDE_SCORE =
|
|
225
|
+
exports.REST_OUTSIDE_SCORE = 50;
|
|
226
226
|
/** Default rest discipline score when no valid rest data exists */
|
|
227
|
-
exports.REST_NO_DATA_SCORE =
|
|
227
|
+
exports.REST_NO_DATA_SCORE = 75;
|