@bailaya/react 1.0.25 → 1.0.27

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.
@@ -1,12 +1,14 @@
1
- import React from 'react';
2
- import type { StudioClass } from '@bailaya/core';
1
+ import React from "react";
2
+ import type { StudioClass } from "@bailaya/core";
3
3
  export interface ClassScheduleProps {
4
4
  /** Optional start date for the 7-day window; defaults to today */
5
5
  from?: Date;
6
6
  /** Optional studio ID to override the default configured ID */
7
7
  overrideId?: string;
8
- /** Locale code for date formatting (e.g. "en", "es"); falls back to browser default */
8
+ /** Locale code for date/price formatting (e.g. "en", "es"); falls back to browser default */
9
9
  locale?: string;
10
+ /** Currency code for price formatting (e.g., "USD", "MXN"). If omitted, shows decimal. */
11
+ currency?: string;
10
12
  /** Custom labels (e.g. for "Instructor:" text) */
11
13
  labels?: {
12
14
  /** Label text for the instructor line; defaults to "Instructor:" */
@@ -16,25 +18,50 @@ export interface ClassScheduleProps {
16
18
  className?: string;
17
19
  /** Each class "card" wrapper */
18
20
  itemClassName?: string;
21
+ /** Wrapper for the inner row (left/right) */
22
+ rowClassName?: string;
23
+ /** Left column (title/meta/instructor) */
24
+ leftClassName?: string;
19
25
  /** Class name element */
20
26
  nameClassName?: string;
27
+ /** Level element "(Beginner)" */
28
+ levelClassName?: string;
21
29
  /** Details (date/time) element */
22
30
  detailsClassName?: string;
23
31
  /** Instructor line element */
24
32
  instructorClassName?: string;
33
+ /** Right column container (price + button) */
34
+ rightClassName?: string;
35
+ /** Price element */
36
+ priceClassName?: string;
37
+ /** Button element */
38
+ buttonClassName?: string;
39
+ /** Text for the Book CTA (i18n). Default: "Book This Class" */
40
+ bookNowText?: string;
41
+ /** Base URL for booking links. Default: "https://www.bailaya.com/book/" */
42
+ bookBaseUrl?: string;
43
+ /** Hide the Book button entirely. Default: false */
44
+ hideBookButton?: boolean;
45
+ /** Custom price formatter (overrides `currency`) */
46
+ formatPrice?: (price: number, cls: StudioClass) => string;
25
47
  /**
26
- * Completely override the default renderItem
48
+ * Optional link renderer.
49
+ * If not provided, a plain <a> will be rendered.
27
50
  */
51
+ renderLink?: (opts: {
52
+ href: string;
53
+ className?: string;
54
+ children: React.ReactNode;
55
+ }) => React.ReactNode;
56
+ /** Completely override the default renderItem */
28
57
  renderItem?: (cls: StudioClass) => React.ReactNode;
29
58
  }
30
59
  /**
31
60
  * Displays an upcoming-class schedule for a studio:
32
- * name + level
33
- * weekday, MM-DD, time
34
- * optional instructor
35
- *
36
- * Uses sensible Tailwind defaults, but you can override
37
- * every slot via props or replace the layout entirely.
61
+ * - name + level
62
+ * - weekday, date, time
63
+ * - optional instructor
64
+ * - RIGHT: price + "Book This Class" CTA
38
65
  */
39
66
  export declare const ClassSchedule: React.FC<ClassScheduleProps>;
40
67
  //# sourceMappingURL=ClassSchedule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClassSchedule.d.ts","sourceRoot":"","sources":["../../src/components/ClassSchedule.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kDAAkD;IAClD,MAAM,CAAC,EAAE;QACP,oEAAoE;QACpE,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yBAAyB;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,KAAK,CAAC,SAAS,CAAA;CACnD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4DtD,CAAA"}
1
+ {"version":3,"file":"ClassSchedule.d.ts","sourceRoot":"","sources":["../../src/components/ClassSchedule.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA4BjD,MAAM,WAAW,kBAAkB;IAC/B,kEAAkE;IAClE,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,kDAAkD;IAClD,MAAM,CAAC,EAAE;QACL,oEAAoE;QACpE,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,oDAAoD;IACpD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,KAAK,MAAM,CAAC;IAE1D;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;KAC7B,KAAK,KAAK,CAAC,SAAS,CAAC;IAEtB,iDAAiD;IACjD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,KAAK,CAAC,SAAS,CAAC;CACtD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA6GtD,CAAC"}
@@ -8,58 +8,94 @@ exports.ClassSchedule = void 0;
8
8
  const react_1 = __importDefault(require("react"));
9
9
  const useClasses_1 = require("../hooks/useClasses");
10
10
  const LoadingIcon_1 = require("./ui/LoadingIcon");
11
+ /** Default price formatter (uses currency if provided; falls back to decimal). */
12
+ function defaultFormatPrice(price, locale, currency) {
13
+ if (Number.isFinite(price)) {
14
+ if (currency) {
15
+ try {
16
+ return new Intl.NumberFormat(locale !== null && locale !== void 0 ? locale : "en", {
17
+ style: "currency",
18
+ currency,
19
+ }).format(price);
20
+ }
21
+ catch (_a) {
22
+ /* ignore invalid currency and fall through */
23
+ }
24
+ }
25
+ return new Intl.NumberFormat(locale !== null && locale !== void 0 ? locale : "en", {
26
+ minimumFractionDigits: 2,
27
+ maximumFractionDigits: 2,
28
+ }).format(price);
29
+ }
30
+ return "";
31
+ }
11
32
  /**
12
33
  * Displays an upcoming-class schedule for a studio:
13
- * name + level
14
- * weekday, MM-DD, time
15
- * optional instructor
16
- *
17
- * Uses sensible Tailwind defaults, but you can override
18
- * every slot via props or replace the layout entirely.
34
+ * - name + level
35
+ * - weekday, date, time
36
+ * - optional instructor
37
+ * - RIGHT: price + "Book This Class" CTA
19
38
  */
20
- const ClassSchedule = ({ from, overrideId, locale, labels = {}, className = 'mt-6 md:mt-12 space-y-4', itemClassName = 'p-4 bg-white rounded-lg shadow', nameClassName = 'font-semibold text-lg', detailsClassName = 'text-sm text-gray-600', instructorClassName = 'text-sm text-gray-800 mt-1', renderItem, }) => {
39
+ const ClassSchedule = ({ from, overrideId, locale, currency, labels = {}, className = "by-scheduleList", itemClassName = "by-scheduleItem", rowClassName = "by-scheduleRow", leftClassName = "by-scheduleLeft", nameClassName = "by-scheduleName", levelClassName = "by-scheduleLevel", detailsClassName = "by-scheduleMeta", instructorClassName = "by-scheduleInstructor", rightClassName = "by-scheduleRight", priceClassName = "by-schedulePrice", buttonClassName = "by-btn by-btnBook", bookNowText = "Book This Class", bookBaseUrl = "https://www.bailaya.com/book/", hideBookButton = false, formatPrice, renderLink, renderItem, }) => {
21
40
  var _a;
22
- const { data: classes, loading: isLoading, error } = (0, useClasses_1.useClasses)(from, overrideId);
23
- const weekdayFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : 'en', { weekday: 'long' });
24
- const dateFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : 'en', { month: 'short', day: 'numeric' });
25
- const instructorLabel = (_a = labels === null || labels === void 0 ? void 0 : labels.instructor) !== null && _a !== void 0 ? _a : 'Instructor:';
26
- if (isLoading) {
27
- return react_1.default.createElement("div", { className: className },
28
- react_1.default.createElement(LoadingIcon_1.LoadingIcon, null));
41
+ const { data: classes, loading, error } = (0, useClasses_1.useClasses)(from, overrideId);
42
+ const weekdayFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : "en", { weekday: "long" });
43
+ const dateFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : "en", {
44
+ month: "short",
45
+ day: "numeric",
46
+ });
47
+ const instructorLabel = (_a = labels === null || labels === void 0 ? void 0 : labels.instructor) !== null && _a !== void 0 ? _a : "Instructor:";
48
+ if (loading) {
49
+ return (react_1.default.createElement("ul", { className: className },
50
+ react_1.default.createElement("li", null,
51
+ react_1.default.createElement(LoadingIcon_1.LoadingIcon, null))));
29
52
  }
30
53
  if (error) {
31
- return react_1.default.createElement("div", { className: className }, error.message);
54
+ return (react_1.default.createElement("ul", { className: className },
55
+ react_1.default.createElement("li", null, error.message)));
32
56
  }
33
57
  return (react_1.default.createElement("ul", { className: className }, classes === null || classes === void 0 ? void 0 : classes.map((cls) => {
34
- const dateObj = cls.date;
35
- const dayName = weekdayFmt.format(dateObj);
36
- const shortDate = dateFmt.format(dateObj);
58
+ const dayName = weekdayFmt.format(cls.date);
59
+ const shortDate = dateFmt.format(cls.date);
37
60
  if (renderItem) {
38
61
  return react_1.default.createElement("li", { key: cls.id }, renderItem(cls));
39
62
  }
63
+ const priceText = formatPrice
64
+ ? formatPrice(cls.price, cls)
65
+ : defaultFormatPrice(cls.price, locale, currency);
66
+ const href = `${bookBaseUrl}${cls.id}`;
40
67
  return (react_1.default.createElement("li", { key: cls.id, className: itemClassName },
41
- react_1.default.createElement("div", null,
42
- react_1.default.createElement("div", { className: nameClassName },
43
- cls.name,
44
- ' ',
45
- react_1.default.createElement("span", { className: "text-sm text-gray-500" },
46
- "(",
47
- cls.level,
48
- ")")),
49
- react_1.default.createElement("div", { className: detailsClassName },
50
- dayName,
51
- ", ",
52
- shortDate,
53
- " \u2014 ",
54
- cls.startTime,
55
- "\u2013",
56
- cls.endTime),
57
- cls.instructor && (react_1.default.createElement("div", { className: instructorClassName },
58
- instructorLabel,
59
- ' ',
60
- react_1.default.createElement("strong", null,
61
- cls.instructor.name,
62
- cls.instructor.lastname ? ` ${cls.instructor.lastname}` : ''))))));
68
+ react_1.default.createElement("div", { className: rowClassName },
69
+ react_1.default.createElement("div", { className: leftClassName },
70
+ react_1.default.createElement("div", { className: nameClassName },
71
+ cls.name,
72
+ " ",
73
+ react_1.default.createElement("span", { className: levelClassName },
74
+ "(",
75
+ cls.level,
76
+ ")")),
77
+ react_1.default.createElement("div", { className: detailsClassName },
78
+ dayName,
79
+ ", ",
80
+ shortDate,
81
+ " \u2014 ",
82
+ cls.startTime,
83
+ "\u2013",
84
+ cls.endTime),
85
+ cls.instructor && (react_1.default.createElement("div", { className: instructorClassName },
86
+ instructorLabel,
87
+ " ",
88
+ react_1.default.createElement("strong", null,
89
+ cls.instructor.name,
90
+ cls.instructor.lastname ? ` ${cls.instructor.lastname}` : "")))),
91
+ react_1.default.createElement("div", { className: rightClassName },
92
+ Number.isFinite(cls.price) && (react_1.default.createElement("div", { className: priceClassName }, priceText)),
93
+ !hideBookButton &&
94
+ (renderLink ? (renderLink({
95
+ href,
96
+ className: buttonClassName,
97
+ children: bookNowText,
98
+ })) : (react_1.default.createElement("a", { href: href, className: buttonClassName }, bookNowText)))))));
63
99
  })));
64
100
  };
65
101
  exports.ClassSchedule = ClassSchedule;
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import type { StudioClass } from '@bailaya/core';
1
+ import React from "react";
2
+ import type { StudioClass } from "@bailaya/core";
3
3
  export interface ClassScheduleByTypeProps {
4
4
  /** The dance type to filter classes by (e.g., "salsa") */
5
5
  typeName: string;
@@ -7,9 +7,11 @@ export interface ClassScheduleByTypeProps {
7
7
  from?: Date;
8
8
  /** Optional studio ID to override the default configured ID */
9
9
  overrideId?: string;
10
- /** Locale code for date formatting (e.g. "en", "es"); falls back to browser default */
10
+ /** Locale code for date/price formatting (e.g. "en", "es"); falls back to browser default */
11
11
  locale?: string;
12
- /** Custom labels (e.g. for "Instructor:" text) */
12
+ /** Currency code for price formatting (e.g., "USD", "MXN"). If omitted, shows decimal. */
13
+ currency?: string;
14
+ /** Custom labels */
13
15
  labels?: {
14
16
  /** Label text for the instructor line; defaults to "Instructor:" */
15
17
  instructor?: string;
@@ -18,12 +20,41 @@ export interface ClassScheduleByTypeProps {
18
20
  className?: string;
19
21
  /** Each class "card" wrapper */
20
22
  itemClassName?: string;
23
+ /** Wrapper for the inner row (left/right) */
24
+ rowClassName?: string;
25
+ /** Left column (title/meta/instructor) */
26
+ leftClassName?: string;
21
27
  /** Class name element */
22
28
  nameClassName?: string;
29
+ /** Level element (the small, muted "(Beginner)" part) */
30
+ levelClassName?: string;
23
31
  /** Details (date/time) element */
24
32
  detailsClassName?: string;
25
33
  /** Instructor line element */
26
34
  instructorClassName?: string;
35
+ /** Right column container (price + button) */
36
+ rightClassName?: string;
37
+ /** Price element */
38
+ priceClassName?: string;
39
+ /** Button element */
40
+ buttonClassName?: string;
41
+ /** Text for the Book CTA (i18n). Default: "Book This Class" */
42
+ bookNowText?: string;
43
+ /** Base URL for booking links. Default: "https://www.bailaya.com/book/" */
44
+ bookBaseUrl?: string;
45
+ /** Hide the Book button entirely. Default: false */
46
+ hideBookButton?: boolean;
47
+ /** Custom price formatter (overrides `currency`) */
48
+ formatPrice?: (price: number, cls: StudioClass) => string;
49
+ /**
50
+ * Optional link renderer.
51
+ * If not provided, a plain <a> will be rendered.
52
+ */
53
+ renderLink?: (opts: {
54
+ href: string;
55
+ className?: string;
56
+ children: React.ReactNode;
57
+ }) => React.ReactNode;
27
58
  /**
28
59
  * Completely override the default render for each item
29
60
  */
@@ -31,12 +62,10 @@ export interface ClassScheduleByTypeProps {
31
62
  }
32
63
  /**
33
64
  * Displays a schedule of upcoming classes of a specific dance type:
34
- * name + level
35
- * weekday, MM-DD, time
36
- * optional instructor
37
- *
38
- * Uses sensible Tailwind defaults but you can override
39
- * every slot via props or bypass with renderItem.
65
+ * - name + level
66
+ * - weekday, date, time
67
+ * - optional instructor
68
+ * - RIGHT: price + "Book This Class" CTA
40
69
  */
41
70
  export declare const ClassScheduleByType: React.FC<ClassScheduleByTypeProps>;
42
71
  //# sourceMappingURL=ClassScheduleByType.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClassScheduleByType.d.ts","sourceRoot":"","sources":["../../src/components/ClassScheduleByType.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,wBAAwB;IACvC,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAA;IAEhB,kEAAkE;IAClE,IAAI,CAAC,EAAE,IAAI,CAAA;IAEX,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf,kDAAkD;IAClD,MAAM,CAAC,EAAE;QACP,oEAAoE;QACpE,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IAED,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yBAAyB;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,KAAK,CAAC,SAAS,CAAA;CACnD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAkElE,CAAA"}
1
+ {"version":3,"file":"ClassScheduleByType.d.ts","sourceRoot":"","sources":["../../src/components/ClassScheduleByType.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA2BjD,MAAM,WAAW,wBAAwB;IACrC,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IAEjB,kEAAkE;IAClE,IAAI,CAAC,EAAE,IAAI,CAAC;IAEZ,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,oBAAoB;IACpB,MAAM,CAAC,EAAE;QACL,oEAAoE;QACpE,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,oDAAoD;IACpD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,KAAK,MAAM,CAAC;IAE1D;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;KAC7B,KAAK,KAAK,CAAC,SAAS,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,KAAK,CAAC,SAAS,CAAC;CACtD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAgHlE,CAAC"}
@@ -7,31 +7,57 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.ClassScheduleByType = void 0;
8
8
  const react_1 = __importDefault(require("react"));
9
9
  const useClassesByType_1 = require("../hooks/useClassesByType");
10
+ /** Format price with optional currency or custom formatter */
11
+ function defaultFormatPrice(price, locale, currency) {
12
+ if (Number.isFinite(price)) {
13
+ if (currency) {
14
+ try {
15
+ return new Intl.NumberFormat(locale !== null && locale !== void 0 ? locale : "en", {
16
+ style: "currency",
17
+ currency,
18
+ }).format(price);
19
+ }
20
+ catch (_a) {
21
+ // Fallback to decimal if currency code is invalid
22
+ }
23
+ }
24
+ return new Intl.NumberFormat(locale !== null && locale !== void 0 ? locale : "en", {
25
+ minimumFractionDigits: 2,
26
+ maximumFractionDigits: 2,
27
+ }).format(price);
28
+ }
29
+ return "";
30
+ }
10
31
  /**
11
32
  * Displays a schedule of upcoming classes of a specific dance type:
12
- * name + level
13
- * weekday, MM-DD, time
14
- * optional instructor
15
- *
16
- * Uses sensible Tailwind defaults but you can override
17
- * every slot via props or bypass with renderItem.
33
+ * - name + level
34
+ * - weekday, date, time
35
+ * - optional instructor
36
+ * - RIGHT: price + "Book This Class" CTA
18
37
  */
19
- const ClassScheduleByType = ({ typeName, from, overrideId, locale, labels = {}, className = 'mt-6 md:mt-12 space-y-4', itemClassName = 'p-4 bg-white rounded-lg shadow', nameClassName = 'font-semibold text-lg', detailsClassName = 'text-sm text-gray-600', instructorClassName = 'text-sm text-gray-800 mt-1', renderItem, }) => {
38
+ const ClassScheduleByType = ({ typeName, from, overrideId, locale, currency, labels = {}, className = "by-scheduleList", itemClassName = "by-scheduleItem", rowClassName = "by-scheduleRow", leftClassName = "by-scheduleLeft", nameClassName = "by-scheduleName", levelClassName = "by-scheduleLevel", detailsClassName = "by-scheduleMeta", instructorClassName = "by-scheduleInstructor", rightClassName = "by-scheduleRight", priceClassName = "by-schedulePrice", buttonClassName = "by-btn by-btnBook", bookNowText = "Book This Class", bookBaseUrl = "https://www.bailaya.com/book/", hideBookButton = false, formatPrice, renderLink, renderItem, }) => {
20
39
  var _a;
21
- const { data: classes, loading: isLoading, error } = (0, useClassesByType_1.useClassesByType)(typeName, from, overrideId);
22
- const weekdayFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : 'en', { weekday: 'long' });
23
- const dateFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : 'en', { month: 'short', day: 'numeric' });
24
- const instructorLabel = (_a = labels === null || labels === void 0 ? void 0 : labels.instructor) !== null && _a !== void 0 ? _a : 'Instructor:';
25
- if (isLoading) {
26
- return react_1.default.createElement("div", { className: className },
27
- "Loading ",
28
- typeName,
29
- " classes...");
40
+ const { data: classes, loading, error } = (0, useClassesByType_1.useClassesByType)(typeName, from, overrideId);
41
+ const weekdayFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : "en", {
42
+ weekday: "long",
43
+ });
44
+ const dateFmt = new Intl.DateTimeFormat(locale !== null && locale !== void 0 ? locale : "en", {
45
+ month: "short",
46
+ day: "numeric",
47
+ });
48
+ const instructorLabel = (_a = labels === null || labels === void 0 ? void 0 : labels.instructor) !== null && _a !== void 0 ? _a : "Instructor:";
49
+ if (loading) {
50
+ return react_1.default.createElement("ul", { className: className },
51
+ react_1.default.createElement("li", null,
52
+ "Loading ",
53
+ typeName,
54
+ " classes..."));
30
55
  }
31
56
  if (error) {
32
- return react_1.default.createElement("div", { className: className },
33
- "Error: ",
34
- error.message);
57
+ return react_1.default.createElement("ul", { className: className },
58
+ react_1.default.createElement("li", null,
59
+ "Error: ",
60
+ error.message));
35
61
  }
36
62
  return (react_1.default.createElement("ul", { className: className }, classes === null || classes === void 0 ? void 0 : classes.map((cls) => {
37
63
  const dateObj = cls.date;
@@ -40,29 +66,44 @@ const ClassScheduleByType = ({ typeName, from, overrideId, locale, labels = {},
40
66
  if (renderItem) {
41
67
  return react_1.default.createElement("li", { key: cls.id }, renderItem(cls));
42
68
  }
69
+ const priceText = formatPrice
70
+ ? formatPrice(cls.price, cls)
71
+ : defaultFormatPrice(cls.price, locale, currency);
72
+ const href = `${bookBaseUrl}${cls.id}`;
43
73
  return (react_1.default.createElement("li", { key: cls.id, className: itemClassName },
44
- react_1.default.createElement("div", null,
45
- react_1.default.createElement("div", { className: nameClassName },
46
- cls.name,
47
- ' ',
48
- react_1.default.createElement("span", { className: "text-sm text-gray-500" },
49
- "(",
50
- cls.level,
51
- ")")),
52
- react_1.default.createElement("div", { className: detailsClassName },
53
- weekday,
54
- ", ",
55
- dateStr,
56
- " \u2014 ",
57
- cls.startTime,
58
- "\u2013",
59
- cls.endTime),
60
- cls.instructor && (react_1.default.createElement("div", { className: instructorClassName },
61
- instructorLabel,
62
- ' ',
63
- react_1.default.createElement("strong", null,
64
- cls.instructor.name,
65
- cls.instructor.lastname ? ` ${cls.instructor.lastname}` : ''))))));
74
+ react_1.default.createElement("div", { className: rowClassName },
75
+ react_1.default.createElement("div", { className: leftClassName },
76
+ react_1.default.createElement("div", { className: nameClassName },
77
+ cls.name,
78
+ " ",
79
+ react_1.default.createElement("span", { className: levelClassName },
80
+ "(",
81
+ cls.level,
82
+ ")")),
83
+ react_1.default.createElement("div", { className: detailsClassName },
84
+ weekday,
85
+ ", ",
86
+ dateStr,
87
+ " \u2014 ",
88
+ cls.startTime,
89
+ "\u2013",
90
+ cls.endTime),
91
+ cls.instructor && (react_1.default.createElement("div", { className: instructorClassName },
92
+ instructorLabel,
93
+ " ",
94
+ react_1.default.createElement("strong", null,
95
+ cls.instructor.name,
96
+ cls.instructor.lastname
97
+ ? ` ${cls.instructor.lastname}`
98
+ : "")))),
99
+ react_1.default.createElement("div", { className: rightClassName },
100
+ Number.isFinite(cls.price) && (react_1.default.createElement("div", { className: priceClassName }, priceText)),
101
+ !hideBookButton &&
102
+ (renderLink ? (renderLink({
103
+ href,
104
+ className: buttonClassName,
105
+ children: bookNowText,
106
+ })) : (react_1.default.createElement("a", { href: href, className: buttonClassName }, bookNowText)))))));
66
107
  })));
67
108
  };
68
109
  exports.ClassScheduleByType = ClassScheduleByType;
package/dist/styles.css CHANGED
@@ -217,3 +217,99 @@
217
217
  font-size: 1.25rem;
218
218
  }
219
219
  }
220
+
221
+ /* Container */
222
+ :where(.by-scheduleList) {
223
+ margin-top: 1.5rem;
224
+ display: flex;
225
+ flex-direction: column;
226
+ row-gap: 1rem;
227
+ }
228
+ @media (min-width: 768px) {
229
+ :where(.by-scheduleList) {
230
+ margin-top: 3rem;
231
+ }
232
+ }
233
+
234
+ /* Item card */
235
+ :where(.by-scheduleItem) {
236
+ padding: 1rem;
237
+ background: #fff;
238
+ border-radius: var(--by-radius-lg);
239
+ box-shadow: var(--by-shadow);
240
+ border: 1px solid var(--by-border);
241
+ }
242
+
243
+ /* Inner row: column on mobile; split left/right on md+ */
244
+ :where(.by-scheduleRow) {
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: 0.75rem;
248
+ }
249
+ @media (min-width: 768px) {
250
+ :where(.by-scheduleRow) {
251
+ flex-direction: row;
252
+ align-items: center;
253
+ justify-content: space-between;
254
+ }
255
+ }
256
+
257
+ /* Left column (title + meta + instructor) */
258
+ :where(.by-scheduleLeft) {
259
+ display: flex;
260
+ flex-direction: column;
261
+ min-width: 0;
262
+ }
263
+
264
+ /* Title: name + level */
265
+ :where(.by-scheduleName) {
266
+ font-weight: 600;
267
+ font-size: 1.125rem;
268
+ color: var(--by-color-heading);
269
+ line-height: 1.2;
270
+ }
271
+ :where(.by-scheduleLevel) {
272
+ margin-left: 0.25rem;
273
+ font-size: 0.875rem;
274
+ opacity: 0.7;
275
+ }
276
+
277
+ /* Meta line: weekday, date, time */
278
+ :where(.by-scheduleMeta) {
279
+ color: var(--by-color-text);
280
+ font-size: 0.875rem;
281
+ }
282
+
283
+ /* Instructor line */
284
+ :where(.by-scheduleInstructor) {
285
+ color: var(--by-color-text);
286
+ font-size: 0.875rem;
287
+ margin-top: 0.25rem;
288
+ }
289
+
290
+ /* Right column: price + button */
291
+ :where(.by-scheduleRight) {
292
+ display: flex;
293
+ align-items: center;
294
+ gap: 1rem;
295
+ }
296
+
297
+ /* Price style */
298
+ :where(.by-schedulePrice) {
299
+ font-weight: 700;
300
+ color: var(--by-color-heading);
301
+ font-size: 1rem;
302
+ }
303
+ @media (min-width: 768px) {
304
+ :where(.by-schedulePrice) {
305
+ font-size: 1.125rem;
306
+ }
307
+ }
308
+
309
+ /* Button: reuse .by-btn base; adjust spacing for this layout */
310
+ :where(.by-btnBook) {
311
+ margin-top: 0; /* override .by-btn's margin if inherited elsewhere */
312
+ }
313
+ :where(.by-scheduleRight .by-btn) {
314
+ margin-top: 0;
315
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bailaya/react",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "A React component library for the BailaYa public API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "typescript": "^5.8.3"
33
33
  },
34
34
  "dependencies": {
35
- "@bailaya/core": "^1.0.6",
35
+ "@bailaya/core": "^1.0.7",
36
36
  "lucide-react": "^0.536.0"
37
37
  },
38
38
  "license": "ISC"