@sudobility/consumables_pages 0.0.2 → 0.0.5

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.
@@ -0,0 +1,2 @@
1
+ import type { CreditBalanceBadgeProps } from "./types";
2
+ export declare function CreditBalanceBadge({ balance, isLoading, onClick, className, }: CreditBalanceBadgeProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function CreditBalanceBadge({ balance, isLoading, onClick, className, }) {
3
+ if (isLoading) {
4
+ return (_jsx("span", { className: `inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium text-gray-400 ${className || ""}`, children: _jsx("span", { className: "animate-pulse", children: "..." }) }));
5
+ }
6
+ if (balance === null)
7
+ return null;
8
+ const Wrapper = onClick ? "button" : "span";
9
+ return (_jsxs(Wrapper, { onClick: onClick, className: `inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${balance > 0
10
+ ? "bg-blue-100 text-blue-700"
11
+ : "bg-red-100 text-red-700"} ${onClick ? "cursor-pointer hover:opacity-80" : ""} ${className || ""}`, children: [_jsx("svg", { className: "w-3.5 h-3.5", fill: "currentColor", viewBox: "0 0 20 20", children: _jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a1 1 0 10-2 0v.092a4.535 4.535 0 00-1.676.662C6.602 6.234 6 7.009 6 8c0 .99.602 1.765 1.324 2.246.48.32 1.054.545 1.676.662v1.941c-.391-.127-.68-.317-.843-.504a1 1 0 10-1.51 1.31c.562.649 1.413 1.076 2.353 1.253V15a1 1 0 102 0v-.092a4.535 4.535 0 001.676-.662C13.398 13.766 14 12.991 14 12c0-.99-.602-1.765-1.324-2.246A4.535 4.535 0 0011 9.092V7.151c.391.127.68.317.843.504a1 1 0 101.511-1.31c-.563-.649-1.413-1.076-2.354-1.253V5z", clipRule: "evenodd" }) }), balance] }));
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { CreditStorePageProps } from "./types";
2
+ export declare function CreditStorePage({ isAuthenticated, balance, packages, isLoading, isPurchasing, error, onPurchase, onLoginClick, labels, formatters, className, }: CreditStorePageProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function CreditStorePage({ isAuthenticated, balance, packages, isLoading, isPurchasing, error, onPurchase, onLoginClick, labels, formatters, className, }) {
3
+ return (_jsxs("div", { className: className, children: [_jsx("h1", { className: "text-2xl font-bold mb-6", children: labels.title }), isAuthenticated && balance !== null && (_jsxs("div", { className: "mb-8 p-4 bg-blue-50 rounded-lg border border-blue-200", children: [_jsx("p", { className: "text-sm text-blue-600 font-medium", children: labels.currentBalanceLabel }), _jsx("p", { className: "text-3xl font-bold text-blue-900", children: formatters.formatCredits(balance) })] })), error && (_jsxs("div", { className: "mb-6 p-4 bg-red-50 rounded-lg border border-red-200", children: [_jsx("p", { className: "text-sm font-medium text-red-800", children: labels.errorTitle }), _jsx("p", { className: "text-sm text-red-600", children: error })] })), !isAuthenticated && (_jsxs("div", { className: "mb-6 p-4 bg-yellow-50 rounded-lg border border-yellow-200", children: [_jsx("p", { className: "text-sm text-yellow-800", children: labels.loginRequired }), _jsx("button", { onClick: onLoginClick, className: "mt-2 px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700", children: "Log in" })] })), isLoading && (_jsx("div", { className: "flex justify-center py-12", children: _jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" }) })), !isLoading && packages.length === 0 && (_jsx("p", { className: "text-gray-500 text-center py-8", children: labels.noProducts })), !isLoading && packages.length > 0 && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: packages.map((pkg) => (_jsx("div", { className: "p-6 bg-white rounded-xl border border-gray-200 shadow-sm hover:shadow-md transition-shadow", children: _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-3xl font-bold text-gray-900", children: formatters.formatCredits(pkg.credits) }), formatters.getPackageDescription && (_jsx("p", { className: "text-sm text-gray-500 mt-1", children: formatters.getPackageDescription(pkg.packageId) })), _jsx("p", { className: "text-xl font-semibold text-blue-600 mt-3", children: pkg.priceString }), _jsx("button", { onClick: () => onPurchase(pkg.packageId), disabled: isPurchasing || !isAuthenticated, className: "mt-4 w-full px-4 py-2.5 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors", children: isPurchasing
4
+ ? labels.purchasingButton
5
+ : labels.purchaseButton })] }) }, pkg.packageId))) }))] }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { PurchaseHistoryPageProps } from "./types";
2
+ export declare function PurchaseHistoryPage({ purchases, isLoading, error, onLoadMore, hasMore, labels, formatters, className, }: PurchaseHistoryPageProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ export function PurchaseHistoryPage({ purchases, isLoading, error, onLoadMore, hasMore, labels, formatters, className, }) {
3
+ return (_jsxs("div", { className: className, children: [_jsx("h1", { className: "text-2xl font-bold mb-6", children: labels.title }), error && (_jsx("div", { className: "mb-4 p-3 bg-red-50 rounded-lg border border-red-200", children: _jsx("p", { className: "text-sm text-red-600", children: error }) })), isLoading && (_jsx("div", { className: "flex justify-center py-12", children: _jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" }) })), !isLoading && purchases.length === 0 && (_jsx("p", { className: "text-gray-500 text-center py-8", children: labels.noRecords })), !isLoading && purchases.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden sm:block overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-gray-200", children: [_jsx("th", { className: "text-left py-3 px-4 font-medium text-gray-500", children: labels.columnDate }), _jsx("th", { className: "text-right py-3 px-4 font-medium text-gray-500", children: labels.columnCredits }), _jsx("th", { className: "text-left py-3 px-4 font-medium text-gray-500", children: labels.columnSource }), _jsx("th", { className: "text-right py-3 px-4 font-medium text-gray-500", children: labels.columnAmount })] }) }), _jsx("tbody", { children: purchases.map((purchase) => (_jsxs("tr", { className: "border-b border-gray-100 hover:bg-gray-50", children: [_jsx("td", { className: "py-3 px-4 text-gray-700", children: formatters.formatDate(purchase.created_at) }), _jsxs("td", { className: "py-3 px-4 text-right font-medium text-green-600", children: ["+", purchase.credits] }), _jsx("td", { className: "py-3 px-4 text-gray-600", children: formatters.formatSource(purchase.source) }), _jsx("td", { className: "py-3 px-4 text-right text-gray-600", children: purchase.price_cents != null && purchase.currency
4
+ ? formatters.formatAmount(purchase.price_cents, purchase.currency)
5
+ : "-" })] }, purchase.id))) })] }) }), _jsx("div", { className: "sm:hidden space-y-3", children: purchases.map((purchase) => (_jsx("div", { className: "p-4 bg-white rounded-lg border border-gray-200", children: _jsxs("div", { className: "flex justify-between items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm text-gray-500", children: formatters.formatDate(purchase.created_at) }), _jsx("p", { className: "text-sm text-gray-600", children: formatters.formatSource(purchase.source) })] }), _jsxs("div", { className: "text-right", children: [_jsxs("p", { className: "font-medium text-green-600", children: ["+", purchase.credits] }), purchase.price_cents != null && purchase.currency && (_jsx("p", { className: "text-sm text-gray-500", children: formatters.formatAmount(purchase.price_cents, purchase.currency) }))] })] }) }, purchase.id))) }), hasMore && onLoadMore && (_jsx("div", { className: "mt-4 text-center", children: _jsx("button", { onClick: onLoadMore, className: "px-4 py-2 text-sm text-blue-600 hover:text-blue-800 font-medium", children: labels.loadMore }) }))] }))] }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { UsageHistoryPageProps } from "./types";
2
+ export declare function UsageHistoryPage({ usages, isLoading, error, onLoadMore, hasMore, labels, formatters, className, }: UsageHistoryPageProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ export function UsageHistoryPage({ usages, isLoading, error, onLoadMore, hasMore, labels, formatters, className, }) {
3
+ return (_jsxs("div", { className: className, children: [_jsx("h1", { className: "text-2xl font-bold mb-6", children: labels.title }), error && (_jsx("div", { className: "mb-4 p-3 bg-red-50 rounded-lg border border-red-200", children: _jsx("p", { className: "text-sm text-red-600", children: error }) })), isLoading && (_jsx("div", { className: "flex justify-center py-12", children: _jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" }) })), !isLoading && usages.length === 0 && (_jsx("p", { className: "text-gray-500 text-center py-8", children: labels.noRecords })), !isLoading && usages.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden sm:block overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-gray-200", children: [_jsx("th", { className: "text-left py-3 px-4 font-medium text-gray-500", children: labels.columnDate }), _jsx("th", { className: "text-left py-3 px-4 font-medium text-gray-500", children: labels.columnFilename })] }) }), _jsx("tbody", { children: usages.map((usage) => (_jsxs("tr", { className: "border-b border-gray-100 hover:bg-gray-50", children: [_jsx("td", { className: "py-3 px-4 text-gray-700", children: formatters.formatDate(usage.created_at) }), _jsx("td", { className: "py-3 px-4 text-gray-600", children: usage.filename || "-" })] }, usage.id))) })] }) }), _jsx("div", { className: "sm:hidden space-y-3", children: usages.map((usage) => (_jsxs("div", { className: "p-4 bg-white rounded-lg border border-gray-200", children: [_jsx("p", { className: "text-sm text-gray-500", children: formatters.formatDate(usage.created_at) }), _jsx("p", { className: "text-sm text-gray-700 font-medium", children: usage.filename || "-" })] }, usage.id))) }), hasMore && onLoadMore && (_jsx("div", { className: "mt-4 text-center", children: _jsx("button", { onClick: onLoadMore, className: "px-4 py-2 text-sm text-blue-600 hover:text-blue-800 font-medium", children: labels.loadMore }) }))] }))] }));
4
+ }
@@ -0,0 +1,5 @@
1
+ export { CreditStorePage } from "./CreditStorePage";
2
+ export { PurchaseHistoryPage } from "./PurchaseHistoryPage";
3
+ export { UsageHistoryPage } from "./UsageHistoryPage";
4
+ export { CreditBalanceBadge } from "./CreditBalanceBadge";
5
+ export type { CreditStorePageProps, CreditStorePageLabels, CreditStorePageFormatters, PurchaseHistoryPageProps, PurchaseHistoryPageLabels, PurchaseHistoryPageFormatters, UsageHistoryPageProps, UsageHistoryPageLabels, UsageHistoryPageFormatters, CreditBalanceBadgeProps, } from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { CreditStorePage } from "./CreditStorePage";
2
+ export { PurchaseHistoryPage } from "./PurchaseHistoryPage";
3
+ export { UsageHistoryPage } from "./UsageHistoryPage";
4
+ export { CreditBalanceBadge } from "./CreditBalanceBadge";
@@ -0,0 +1,80 @@
1
+ import type { CreditPackage } from "@sudobility/consumables_client";
2
+ import type { ConsumablePurchaseRecord, ConsumableUsageRecord } from "@sudobility/types";
3
+ export interface CreditStorePageLabels {
4
+ title: string;
5
+ currentBalanceLabel: string;
6
+ creditsUnit: string;
7
+ purchaseButton: string;
8
+ purchasingButton: string;
9
+ noProducts: string;
10
+ errorTitle: string;
11
+ loginRequired: string;
12
+ }
13
+ export interface CreditStorePageFormatters {
14
+ formatCredits: (count: number) => string;
15
+ getPackageDescription?: (packageId: string) => string;
16
+ }
17
+ export interface CreditStorePageProps {
18
+ isAuthenticated: boolean;
19
+ balance: number | null;
20
+ packages: CreditPackage[];
21
+ isLoading: boolean;
22
+ isPurchasing: boolean;
23
+ error: string | null;
24
+ onPurchase: (packageId: string) => Promise<void>;
25
+ onLoginClick: () => void;
26
+ labels: CreditStorePageLabels;
27
+ formatters: CreditStorePageFormatters;
28
+ className?: string;
29
+ }
30
+ export interface PurchaseHistoryPageLabels {
31
+ title: string;
32
+ columnDate: string;
33
+ columnCredits: string;
34
+ columnSource: string;
35
+ columnProduct: string;
36
+ columnAmount: string;
37
+ noRecords: string;
38
+ loadMore: string;
39
+ }
40
+ export interface PurchaseHistoryPageFormatters {
41
+ formatDate: (dateStr: string) => string;
42
+ formatAmount: (cents: number, currency: string) => string;
43
+ formatSource: (source: string) => string;
44
+ }
45
+ export interface PurchaseHistoryPageProps {
46
+ purchases: ConsumablePurchaseRecord[];
47
+ isLoading: boolean;
48
+ error: string | null;
49
+ onLoadMore?: () => void;
50
+ hasMore?: boolean;
51
+ labels: PurchaseHistoryPageLabels;
52
+ formatters: PurchaseHistoryPageFormatters;
53
+ className?: string;
54
+ }
55
+ export interface UsageHistoryPageLabels {
56
+ title: string;
57
+ columnDate: string;
58
+ columnFilename: string;
59
+ noRecords: string;
60
+ loadMore: string;
61
+ }
62
+ export interface UsageHistoryPageFormatters {
63
+ formatDate: (dateStr: string) => string;
64
+ }
65
+ export interface UsageHistoryPageProps {
66
+ usages: ConsumableUsageRecord[];
67
+ isLoading: boolean;
68
+ error: string | null;
69
+ onLoadMore?: () => void;
70
+ hasMore?: boolean;
71
+ labels: UsageHistoryPageLabels;
72
+ formatters: UsageHistoryPageFormatters;
73
+ className?: string;
74
+ }
75
+ export interface CreditBalanceBadgeProps {
76
+ balance: number | null;
77
+ isLoading: boolean;
78
+ onClick?: () => void;
79
+ className?: string;
80
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/consumables_pages",
3
- "version": "0.0.2",
3
+ "version": "0.0.5",
4
4
  "description": "Web UI components for consumable credits (credit store, purchase history, usage history)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  "CLAUDE.md"
18
18
  ],
19
19
  "scripts": {
20
- "build": "tsc",
20
+ "build": "tsc -p tsconfig.build.json",
21
21
  "dev": "tsc --watch",
22
22
  "clean": "rm -rf dist",
23
23
  "typecheck": "bunx tsc --noEmit",
@@ -29,11 +29,13 @@
29
29
  "prepublishOnly": "bun run build"
30
30
  },
31
31
  "peerDependencies": {
32
+ "@sudobility/consumables_client": "^0.0.3",
33
+ "@sudobility/types": "^1.9.51",
32
34
  "react": "^18.0.0 || ^19.0.0",
33
35
  "react-dom": "^18.0.0 || ^19.0.0"
34
36
  },
35
37
  "devDependencies": {
36
- "@sudobility/consumables_client": "^0.0.2",
38
+ "@sudobility/consumables_client": "^0.0.3",
37
39
  "@testing-library/jest-dom": "^6.9.1",
38
40
  "@testing-library/react": "^16.3.2",
39
41
  "@types/bun": "^1.2.8",