@bash-app/bash-common 30.176.0 → 30.178.0
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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/__tests__/birthdayExperienceQuality.test.d.ts +2 -0
- package/dist/utils/__tests__/birthdayExperienceQuality.test.d.ts.map +1 -0
- package/dist/utils/__tests__/birthdayExperienceQuality.test.js +22 -0
- package/dist/utils/__tests__/birthdayExperienceQuality.test.js.map +1 -0
- package/dist/utils/birthdayExperienceQuality.d.ts +21 -0
- package/dist/utils/birthdayExperienceQuality.d.ts.map +1 -0
- package/dist/utils/birthdayExperienceQuality.js +33 -0
- package/dist/utils/birthdayExperienceQuality.js.map +1 -0
- package/package.json +1 -1
- package/prisma/schema.prisma +20 -0
- package/src/index.ts +1 -0
- package/src/utils/__tests__/birthdayExperienceQuality.test.ts +34 -0
- package/src/utils/birthdayExperienceQuality.ts +49 -0
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export * from "./utils/entityUtils.js";
|
|
|
34
34
|
export * from "./utils/generalDateTimeUtils.js";
|
|
35
35
|
export * from "./utils/luxonUtils.js";
|
|
36
36
|
export * from "./utils/mathUtils.js";
|
|
37
|
+
export * from "./utils/birthdayExperienceQuality.js";
|
|
37
38
|
export * from "./utils/service/apiServiceBookingApiUtils.js";
|
|
38
39
|
export * from "./utils/service/frontendServiceBookingUtils.js";
|
|
39
40
|
export * from "./utils/service/serviceBookingStatusUtils.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAG3C,YAAY,EACV,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,OAAO,GACR,MAAM,gBAAgB,CAAC;AAExB,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAG9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EACR,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,QAAQ,EAAE,sBAAsB,EAAE,cAAc,EACjE,MAAM,sBAAsB,CAAC;AAG9B,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAG3C,YAAY,EACV,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,OAAO,GACR,MAAM,gBAAgB,CAAC;AAExB,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAG9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,YAAY,EACR,WAAW,EAAE,YAAY,EACzB,YAAY,EAAE,QAAQ,EAAE,sBAAsB,EAAE,cAAc,EACjE,MAAM,sBAAsB,CAAC;AAG9B,cAAc,+BAA+B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ export * from "./utils/entityUtils.js";
|
|
|
34
34
|
export * from "./utils/generalDateTimeUtils.js";
|
|
35
35
|
export * from "./utils/luxonUtils.js";
|
|
36
36
|
export * from "./utils/mathUtils.js";
|
|
37
|
+
export * from "./utils/birthdayExperienceQuality.js";
|
|
37
38
|
export * from "./utils/service/apiServiceBookingApiUtils.js";
|
|
38
39
|
export * from "./utils/service/frontendServiceBookingUtils.js";
|
|
39
40
|
export * from "./utils/service/serviceBookingStatusUtils.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAa3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,+DAA+D;AAC/D,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAE9C,iFAAiF;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAM3D,kBAAkB;AAClB,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAa3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,+DAA+D;AAC/D,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAE9C,iFAAiF;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAM3D,kBAAkB;AAClB,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"birthdayExperienceQuality.test.d.ts","sourceRoot":"","sources":["../../../src/utils/__tests__/birthdayExperienceQuality.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { averageExperienceStars, EXPERIENCE_STAR_BANDS, } from "../birthdayExperienceQuality.js";
|
|
2
|
+
describe("averageExperienceStars", () => {
|
|
3
|
+
it("returns null when there are no votes", () => {
|
|
4
|
+
expect(averageExperienceStars({ Awesome: 0, Okay: 0, Lame: 0 })).toBeNull();
|
|
5
|
+
expect(averageExperienceStars(undefined)).toBeNull();
|
|
6
|
+
});
|
|
7
|
+
it("returns midpoint when all votes are one tier", () => {
|
|
8
|
+
const awesomeMid = (EXPERIENCE_STAR_BANDS.Awesome.min +
|
|
9
|
+
EXPERIENCE_STAR_BANDS.Awesome.max) /
|
|
10
|
+
2;
|
|
11
|
+
expect(averageExperienceStars({ Awesome: 2, Okay: 0, Lame: 0 })).toBeCloseTo(awesomeMid);
|
|
12
|
+
});
|
|
13
|
+
it("blends mixed votes", () => {
|
|
14
|
+
const awesomeMid = (EXPERIENCE_STAR_BANDS.Awesome.min +
|
|
15
|
+
EXPERIENCE_STAR_BANDS.Awesome.max) /
|
|
16
|
+
2;
|
|
17
|
+
const lameMid = (EXPERIENCE_STAR_BANDS.Lame.min + EXPERIENCE_STAR_BANDS.Lame.max) / 2;
|
|
18
|
+
const a = averageExperienceStars({ Awesome: 1, Okay: 0, Lame: 1 });
|
|
19
|
+
expect(a).toBeCloseTo((awesomeMid + lameMid) / 2);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=birthdayExperienceQuality.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"birthdayExperienceQuality.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/birthdayExperienceQuality.test.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,iCAAiC,CAAC;AAEzC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CACJ,sBAAsB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CACzD,CAAC,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,UAAU,GACd,CAAC,qBAAqB,CAAC,OAAO,CAAC,GAAG;YAChC,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC;YACpC,CAAC,CAAC;QACJ,MAAM,CACJ,sBAAsB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CACzD,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,UAAU,GACd,CAAC,qBAAqB,CAAC,OAAO,CAAC,GAAG;YAChC,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC;YACpC,CAAC,CAAC;QACJ,MAAM,OAAO,GACX,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,sBAAsB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Quality of Experience math for birthday freebie catalog offers.
|
|
3
|
+
* Vote tiers map to star bands; the displayed score is a weighted average of band midpoints (0–5).
|
|
4
|
+
*/
|
|
5
|
+
export type BirthdayExperienceVoteTier = "Awesome" | "Okay" | "Lame";
|
|
6
|
+
export interface BirthdayExperienceVoteCounts {
|
|
7
|
+
Awesome: number;
|
|
8
|
+
Okay: number;
|
|
9
|
+
Lame: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const EXPERIENCE_STAR_BANDS: Record<BirthdayExperienceVoteTier, {
|
|
12
|
+
min: number;
|
|
13
|
+
max: number;
|
|
14
|
+
label: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Weighted average of midpoint stars for each vote tier. Null when there are no votes.
|
|
18
|
+
*/
|
|
19
|
+
export declare function averageExperienceStars(votes: BirthdayExperienceVoteCounts | null | undefined): number | null;
|
|
20
|
+
export declare function formatExperienceStars(value: number): string;
|
|
21
|
+
//# sourceMappingURL=birthdayExperienceQuality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"birthdayExperienceQuality.d.ts","sourceRoot":"","sources":["../../src/utils/birthdayExperienceQuality.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,0BAA0B,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAErE,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,qBAAqB,EAAE,MAAM,CACxC,0BAA0B,EAC1B;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAK5C,CAAC;AAUF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACrD,MAAM,GAAG,IAAI,CASf;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Quality of Experience math for birthday freebie catalog offers.
|
|
3
|
+
* Vote tiers map to star bands; the displayed score is a weighted average of band midpoints (0–5).
|
|
4
|
+
*/
|
|
5
|
+
export const EXPERIENCE_STAR_BANDS = {
|
|
6
|
+
Lame: { min: 0, max: 1.999, label: "0–2.0" },
|
|
7
|
+
Okay: { min: 2.0, max: 3.499, label: "2.0–3.5" },
|
|
8
|
+
Awesome: { min: 3.5, max: 5.0, label: "3.5–5.0" },
|
|
9
|
+
};
|
|
10
|
+
const MIDPOINT = {
|
|
11
|
+
Lame: (EXPERIENCE_STAR_BANDS.Lame.min + EXPERIENCE_STAR_BANDS.Lame.max) / 2,
|
|
12
|
+
Okay: (EXPERIENCE_STAR_BANDS.Okay.min + EXPERIENCE_STAR_BANDS.Okay.max) / 2,
|
|
13
|
+
Awesome: (EXPERIENCE_STAR_BANDS.Awesome.min + EXPERIENCE_STAR_BANDS.Awesome.max) /
|
|
14
|
+
2,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Weighted average of midpoint stars for each vote tier. Null when there are no votes.
|
|
18
|
+
*/
|
|
19
|
+
export function averageExperienceStars(votes) {
|
|
20
|
+
if (!votes)
|
|
21
|
+
return null;
|
|
22
|
+
const n = votes.Awesome + votes.Okay + votes.Lame;
|
|
23
|
+
if (n === 0)
|
|
24
|
+
return null;
|
|
25
|
+
const sum = votes.Awesome * MIDPOINT.Awesome +
|
|
26
|
+
votes.Okay * MIDPOINT.Okay +
|
|
27
|
+
votes.Lame * MIDPOINT.Lame;
|
|
28
|
+
return sum / n;
|
|
29
|
+
}
|
|
30
|
+
export function formatExperienceStars(value) {
|
|
31
|
+
return value.toFixed(1);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=birthdayExperienceQuality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"birthdayExperienceQuality.js","sourceRoot":"","sources":["../../src/utils/birthdayExperienceQuality.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,CAAC,MAAM,qBAAqB,GAG9B;IACF,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;IAC5C,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE;IAChD,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE;CAClD,CAAC;AAEF,MAAM,QAAQ,GAA+C;IAC3D,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3E,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3E,OAAO,EACL,CAAC,qBAAqB,CAAC,OAAO,CAAC,GAAG,GAAG,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC;QACvE,CAAC;CACJ,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAsD;IAEtD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,GAAG,GACP,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO;QAChC,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI;QAC1B,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC7B,OAAO,GAAG,GAAG,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
package/prisma/schema.prisma
CHANGED
|
@@ -1708,6 +1708,7 @@ model User {
|
|
|
1708
1708
|
birthdayRewardFavorites BirthdayRewardFavorite[]
|
|
1709
1709
|
birthdayDealSuggestions BirthdayDealSuggestion[]
|
|
1710
1710
|
rewardReports RewardReport[]
|
|
1711
|
+
birthdayFreebieVotes BirthdayFreebieVote[]
|
|
1711
1712
|
rewardReportsReviewed RewardReport[] @relation("RewardReportReviewedBy")
|
|
1712
1713
|
nationalChainReports NationalChainReport[]
|
|
1713
1714
|
nationalChainReportsReviewed NationalChainReport[] @relation("NationalChainReportReviewedBy")
|
|
@@ -6056,6 +6057,8 @@ model BirthdayFreebieCatalog {
|
|
|
6056
6057
|
partner BirthdayOfferPartner? @relation(fields: [partnerId], references: [id], onDelete: SetNull)
|
|
6057
6058
|
suggestion BirthdayDealSuggestion? @relation(fields: [suggestionId], references: [id], onDelete: SetNull)
|
|
6058
6059
|
rewardReports RewardReport[]
|
|
6060
|
+
/// User quality votes (Awesome / Okay / Lame); one row per user per catalog entry.
|
|
6061
|
+
votes BirthdayFreebieVote[]
|
|
6059
6062
|
|
|
6060
6063
|
@@index([stateSlug, citySlug])
|
|
6061
6064
|
@@index([isActive])
|
|
@@ -6063,6 +6066,23 @@ model BirthdayFreebieCatalog {
|
|
|
6063
6066
|
@@index([sector])
|
|
6064
6067
|
}
|
|
6065
6068
|
|
|
6069
|
+
/// User quality vote on a catalog entry (Awesome / Okay / Lame). Drives aggregate counts and optional qualityTier updates.
|
|
6070
|
+
model BirthdayFreebieVote {
|
|
6071
|
+
id String @id @default(cuid())
|
|
6072
|
+
catalogId String
|
|
6073
|
+
userId String
|
|
6074
|
+
tier BirthdayOfferQualityTier
|
|
6075
|
+
createdAt DateTime @default(now())
|
|
6076
|
+
updatedAt DateTime @updatedAt
|
|
6077
|
+
|
|
6078
|
+
catalog BirthdayFreebieCatalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
|
|
6079
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
6080
|
+
|
|
6081
|
+
@@unique([catalogId, userId])
|
|
6082
|
+
@@index([catalogId])
|
|
6083
|
+
@@index([userId])
|
|
6084
|
+
}
|
|
6085
|
+
|
|
6066
6086
|
// Per-city "free things to do" links (tourism calendar, Eventbrite, Meetup, alt-weekly)
|
|
6067
6087
|
enum BirthdayCityResourceType {
|
|
6068
6088
|
TourismCalendar
|
package/src/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ export * from "./utils/entityUtils.js";
|
|
|
46
46
|
export * from "./utils/generalDateTimeUtils.js";
|
|
47
47
|
export * from "./utils/luxonUtils.js";
|
|
48
48
|
export * from "./utils/mathUtils.js";
|
|
49
|
+
export * from "./utils/birthdayExperienceQuality.js";
|
|
49
50
|
export * from "./utils/service/apiServiceBookingApiUtils.js";
|
|
50
51
|
export * from "./utils/service/frontendServiceBookingUtils.js";
|
|
51
52
|
export * from "./utils/service/serviceBookingStatusUtils.js";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
averageExperienceStars,
|
|
3
|
+
EXPERIENCE_STAR_BANDS,
|
|
4
|
+
} from "../birthdayExperienceQuality.js";
|
|
5
|
+
|
|
6
|
+
describe("averageExperienceStars", () => {
|
|
7
|
+
it("returns null when there are no votes", () => {
|
|
8
|
+
expect(
|
|
9
|
+
averageExperienceStars({ Awesome: 0, Okay: 0, Lame: 0 })
|
|
10
|
+
).toBeNull();
|
|
11
|
+
expect(averageExperienceStars(undefined)).toBeNull();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("returns midpoint when all votes are one tier", () => {
|
|
15
|
+
const awesomeMid =
|
|
16
|
+
(EXPERIENCE_STAR_BANDS.Awesome.min +
|
|
17
|
+
EXPERIENCE_STAR_BANDS.Awesome.max) /
|
|
18
|
+
2;
|
|
19
|
+
expect(
|
|
20
|
+
averageExperienceStars({ Awesome: 2, Okay: 0, Lame: 0 })
|
|
21
|
+
).toBeCloseTo(awesomeMid);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("blends mixed votes", () => {
|
|
25
|
+
const awesomeMid =
|
|
26
|
+
(EXPERIENCE_STAR_BANDS.Awesome.min +
|
|
27
|
+
EXPERIENCE_STAR_BANDS.Awesome.max) /
|
|
28
|
+
2;
|
|
29
|
+
const lameMid =
|
|
30
|
+
(EXPERIENCE_STAR_BANDS.Lame.min + EXPERIENCE_STAR_BANDS.Lame.max) / 2;
|
|
31
|
+
const a = averageExperienceStars({ Awesome: 1, Okay: 0, Lame: 1 });
|
|
32
|
+
expect(a).toBeCloseTo((awesomeMid + lameMid) / 2);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Quality of Experience math for birthday freebie catalog offers.
|
|
3
|
+
* Vote tiers map to star bands; the displayed score is a weighted average of band midpoints (0–5).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type BirthdayExperienceVoteTier = "Awesome" | "Okay" | "Lame";
|
|
7
|
+
|
|
8
|
+
export interface BirthdayExperienceVoteCounts {
|
|
9
|
+
Awesome: number;
|
|
10
|
+
Okay: number;
|
|
11
|
+
Lame: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const EXPERIENCE_STAR_BANDS: Record<
|
|
15
|
+
BirthdayExperienceVoteTier,
|
|
16
|
+
{ min: number; max: number; label: string }
|
|
17
|
+
> = {
|
|
18
|
+
Lame: { min: 0, max: 1.999, label: "0–2.0" },
|
|
19
|
+
Okay: { min: 2.0, max: 3.499, label: "2.0–3.5" },
|
|
20
|
+
Awesome: { min: 3.5, max: 5.0, label: "3.5–5.0" },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const MIDPOINT: Record<BirthdayExperienceVoteTier, number> = {
|
|
24
|
+
Lame: (EXPERIENCE_STAR_BANDS.Lame.min + EXPERIENCE_STAR_BANDS.Lame.max) / 2,
|
|
25
|
+
Okay: (EXPERIENCE_STAR_BANDS.Okay.min + EXPERIENCE_STAR_BANDS.Okay.max) / 2,
|
|
26
|
+
Awesome:
|
|
27
|
+
(EXPERIENCE_STAR_BANDS.Awesome.min + EXPERIENCE_STAR_BANDS.Awesome.max) /
|
|
28
|
+
2,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Weighted average of midpoint stars for each vote tier. Null when there are no votes.
|
|
33
|
+
*/
|
|
34
|
+
export function averageExperienceStars(
|
|
35
|
+
votes: BirthdayExperienceVoteCounts | null | undefined
|
|
36
|
+
): number | null {
|
|
37
|
+
if (!votes) return null;
|
|
38
|
+
const n = votes.Awesome + votes.Okay + votes.Lame;
|
|
39
|
+
if (n === 0) return null;
|
|
40
|
+
const sum =
|
|
41
|
+
votes.Awesome * MIDPOINT.Awesome +
|
|
42
|
+
votes.Okay * MIDPOINT.Okay +
|
|
43
|
+
votes.Lame * MIDPOINT.Lame;
|
|
44
|
+
return sum / n;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function formatExperienceStars(value: number): string {
|
|
48
|
+
return value.toFixed(1);
|
|
49
|
+
}
|