@rovela-ai/sdk 0.4.0 → 0.4.2
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/checkout/server/create-checkout-session.d.ts +10 -1
- package/dist/checkout/server/create-checkout-session.d.ts.map +1 -1
- package/dist/checkout/server/create-checkout-session.js +28 -17
- package/dist/checkout/server/create-checkout-session.js.map +1 -1
- package/dist/checkout/server/handle-webhook.js +22 -2
- package/dist/checkout/server/handle-webhook.js.map +1 -1
- package/dist/checkout/server/order-service.d.ts +7 -1
- package/dist/checkout/server/order-service.d.ts.map +1 -1
- package/dist/checkout/server/order-service.js +59 -12
- package/dist/checkout/server/order-service.js.map +1 -1
- package/dist/core/db/queries.d.ts +6 -6
- package/dist/core/db/schema.d.ts +4 -4
- package/package.json +2 -2
- package/dist/admin/api/auth.d.ts +0 -32
- package/dist/admin/api/auth.d.ts.map +0 -1
- package/dist/admin/api/auth.js +0 -37
- package/dist/admin/api/auth.js.map +0 -1
- package/dist/admin/components/AdminSetupForm.d.ts +0 -28
- package/dist/admin/components/AdminSetupForm.d.ts.map +0 -1
- package/dist/admin/components/AdminSetupForm.js +0 -85
- package/dist/admin/components/AdminSetupForm.js.map +0 -1
- package/dist/auth/api/auth.d.ts +0 -9
- package/dist/auth/api/auth.d.ts.map +0 -1
- package/dist/auth/api/auth.js +0 -9
- package/dist/auth/api/auth.js.map +0 -1
- package/dist/auth/server/email-sender.d.ts +0 -64
- package/dist/auth/server/email-sender.d.ts.map +0 -1
- package/dist/auth/server/email-sender.js +0 -106
- package/dist/auth/server/email-sender.js.map +0 -1
- package/dist/products/components/CategoryNav.d.ts +0 -51
- package/dist/products/components/CategoryNav.d.ts.map +0 -1
- package/dist/products/components/CategoryNav.js +0 -110
- package/dist/products/components/CategoryNav.js.map +0 -1
- package/dist/products/components/ProductBreadcrumb.d.ts +0 -52
- package/dist/products/components/ProductBreadcrumb.d.ts.map +0 -1
- package/dist/products/components/ProductBreadcrumb.js +0 -73
- package/dist/products/components/ProductBreadcrumb.js.map +0 -1
- package/dist/products/components/ProductFilters.d.ts +0 -70
- package/dist/products/components/ProductFilters.d.ts.map +0 -1
- package/dist/products/components/ProductFilters.js +0 -125
- package/dist/products/components/ProductFilters.js.map +0 -1
- package/dist/products/hooks/useCategories.d.ts +0 -56
- package/dist/products/hooks/useCategories.d.ts.map +0 -1
- package/dist/products/hooks/useCategories.js +0 -126
- package/dist/products/hooks/useCategories.js.map +0 -1
- package/dist/products/hooks/useProductAttributes.d.ts +0 -59
- package/dist/products/hooks/useProductAttributes.d.ts.map +0 -1
- package/dist/products/hooks/useProductAttributes.js +0 -125
- package/dist/products/hooks/useProductAttributes.js.map +0 -1
- package/dist/theme/ThemeProvider.d.ts +0 -70
- package/dist/theme/ThemeProvider.d.ts.map +0 -1
- package/dist/theme/ThemeProvider.js +0 -75
- package/dist/theme/ThemeProvider.js.map +0 -1
- package/dist/theme/hooks.d.ts +0 -110
- package/dist/theme/hooks.d.ts.map +0 -1
- package/dist/theme/hooks.js +0 -101
- package/dist/theme/hooks.js.map +0 -1
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
/**
|
|
4
|
-
* @rovela/sdk/products/components/ProductBreadcrumb
|
|
5
|
-
*
|
|
6
|
-
* Breadcrumb navigation for product and category pages.
|
|
7
|
-
*/
|
|
8
|
-
import Link from 'next/link';
|
|
9
|
-
import { ChevronRight } from 'lucide-react';
|
|
10
|
-
import { cn } from '../../core/utils';
|
|
11
|
-
// =============================================================================
|
|
12
|
-
// Component
|
|
13
|
-
// =============================================================================
|
|
14
|
-
/**
|
|
15
|
-
* ProductBreadcrumb component for navigation context.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* import { ProductBreadcrumb, useCategories } from '@rovela/sdk/products'
|
|
20
|
-
*
|
|
21
|
-
* function ProductPage({ product, categorySlug }) {
|
|
22
|
-
* const { getBreadcrumb, getCategoryBySlug } = useCategories()
|
|
23
|
-
* const category = getCategoryBySlug(categorySlug)
|
|
24
|
-
* const categoryPath = category ? getBreadcrumb(category.id) : []
|
|
25
|
-
*
|
|
26
|
-
* return (
|
|
27
|
-
* <div>
|
|
28
|
-
* <ProductBreadcrumb
|
|
29
|
-
* categories={categoryPath}
|
|
30
|
-
* product={product}
|
|
31
|
-
* showHome
|
|
32
|
-
* />
|
|
33
|
-
* {// ... product content}
|
|
34
|
-
* </div>
|
|
35
|
-
* )
|
|
36
|
-
* }
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export function ProductBreadcrumb({ categories = [], product, className, showHome = true, homeLabel = 'Home', homeHref = '/', categoryHrefPattern = '/categories/[slug]', separator, items: customItems, }) {
|
|
40
|
-
// Build breadcrumb items
|
|
41
|
-
const items = [];
|
|
42
|
-
if (customItems) {
|
|
43
|
-
// Use custom items if provided
|
|
44
|
-
items.push(...customItems);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
// Build from categories and product
|
|
48
|
-
if (showHome) {
|
|
49
|
-
items.push({ label: homeLabel, href: homeHref });
|
|
50
|
-
}
|
|
51
|
-
// Add "Shop" or "Products" link
|
|
52
|
-
items.push({ label: 'Products', href: '/products' });
|
|
53
|
-
// Add category path
|
|
54
|
-
categories.forEach((category) => {
|
|
55
|
-
items.push({
|
|
56
|
-
label: category.name,
|
|
57
|
-
href: categoryHrefPattern.replace('[slug]', category.slug),
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
// Add product (no link, it's the current page)
|
|
61
|
-
if (product) {
|
|
62
|
-
items.push({ label: product.name });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const defaultSeparator = (_jsx(ChevronRight, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground" }));
|
|
66
|
-
return (_jsx("nav", { className: cn('flex items-center text-sm', className), "aria-label": "Breadcrumb", children: _jsx("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
|
|
67
|
-
const isLast = index === items.length - 1;
|
|
68
|
-
return (_jsxs("li", { className: "flex items-center gap-1.5", children: [index > 0 && (_jsx("span", { className: "flex-shrink-0", "aria-hidden": "true", children: separator || defaultSeparator })), item.href && !isLast ? (_jsx(Link, { href: item.href, className: "text-muted-foreground transition-colors hover:text-foreground", children: item.label })) : (_jsx("span", { className: cn(isLast
|
|
69
|
-
? 'font-medium text-foreground'
|
|
70
|
-
: 'text-muted-foreground'), "aria-current": isLast ? 'page' : undefined, children: item.label }))] }, index));
|
|
71
|
-
}) }) }));
|
|
72
|
-
}
|
|
73
|
-
//# sourceMappingURL=ProductBreadcrumb.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProductBreadcrumb.js","sourceRoot":"","sources":["../../../src/products/components/ProductBreadcrumb.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;GAIG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAiCrC,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,UAAU,GAAG,EAAE,EACf,OAAO,EACP,SAAS,EACT,QAAQ,GAAG,IAAI,EACf,SAAS,GAAG,MAAM,EAClB,QAAQ,GAAG,GAAG,EACd,mBAAmB,GAAG,oBAAoB,EAC1C,SAAS,EACT,KAAK,EAAE,WAAW,GACK;IACvB,yBAAyB;IACzB,MAAM,KAAK,GAAqB,EAAE,CAAA;IAElC,IAAI,WAAW,EAAE,CAAC;QAChB,+BAA+B;QAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAA;IAC5B,CAAC;SAAM,CAAC;QACN,oCAAoC;QACpC,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;QAClD,CAAC;QAED,gCAAgC;QAChC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAA;QAEpD,oBAAoB;QACpB,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC9B,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK,EAAE,QAAQ,CAAC,IAAI;gBACpB,IAAI,EAAE,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC;aAC3D,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,+CAA+C;QAC/C,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,GAAG,CACvB,KAAC,YAAY,IAAC,SAAS,EAAC,6CAA6C,GAAG,CACzE,CAAA;IAED,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CAAC,2BAA2B,EAAE,SAAS,CAAC,gBAC1C,YAAY,YAEvB,aAAI,SAAS,EAAC,qCAAqC,YAChD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBACzB,MAAM,MAAM,GAAG,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;gBAEzC,OAAO,CACL,cAAgB,SAAS,EAAC,2BAA2B,aAClD,KAAK,GAAG,CAAC,IAAI,CACZ,eAAM,SAAS,EAAC,eAAe,iBAAa,MAAM,YAC/C,SAAS,IAAI,gBAAgB,GACzB,CACR,EAEA,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CACtB,KAAC,IAAI,IACH,IAAI,EAAE,IAAI,CAAC,IAAI,EACf,SAAS,EAAC,+DAA+D,YAExE,IAAI,CAAC,KAAK,GACN,CACR,CAAC,CAAC,CAAC,CACF,eACE,SAAS,EAAE,EAAE,CACX,MAAM;gCACJ,CAAC,CAAC,6BAA6B;gCAC/B,CAAC,CAAC,uBAAuB,CAC5B,kBACa,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,YAExC,IAAI,CAAC,KAAK,GACN,CACR,KAzBM,KAAK,CA0BT,CACN,CAAA;YACH,CAAC,CAAC,GACC,GACD,CACP,CAAA;AACH,CAAC"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { ProductAttribute, PriceRange } from '../hooks/useProductAttributes';
|
|
2
|
-
import type { Category } from '../../core/types';
|
|
3
|
-
export interface ProductFilterValues {
|
|
4
|
-
categories: string[];
|
|
5
|
-
attributes: Record<string, string[]>;
|
|
6
|
-
priceRange: {
|
|
7
|
-
min?: number;
|
|
8
|
-
max?: number;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
export interface ProductFilterPanelProps {
|
|
12
|
-
/** Available attributes for filtering */
|
|
13
|
-
attributes?: ProductAttribute[];
|
|
14
|
-
/** Price range for price filter */
|
|
15
|
-
priceRange?: PriceRange | null;
|
|
16
|
-
/** Categories for category filter */
|
|
17
|
-
categories?: Category[];
|
|
18
|
-
/** Current filter values */
|
|
19
|
-
values: ProductFilterValues;
|
|
20
|
-
/** Callback when filters change */
|
|
21
|
-
onChange: (values: ProductFilterValues) => void;
|
|
22
|
-
/** Custom className */
|
|
23
|
-
className?: string;
|
|
24
|
-
/** Currency for price display */
|
|
25
|
-
currency?: string;
|
|
26
|
-
/** Locale for price formatting */
|
|
27
|
-
locale?: string;
|
|
28
|
-
/** Show category filter */
|
|
29
|
-
showCategories?: boolean;
|
|
30
|
-
/** Show price filter */
|
|
31
|
-
showPriceFilter?: boolean;
|
|
32
|
-
/** Collapsible sections */
|
|
33
|
-
collapsible?: boolean;
|
|
34
|
-
/** Initially expanded sections */
|
|
35
|
-
defaultExpanded?: string[];
|
|
36
|
-
/** Show clear all button */
|
|
37
|
-
showClearAll?: boolean;
|
|
38
|
-
/** Layout direction */
|
|
39
|
-
layout?: 'vertical' | 'horizontal';
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* ProductFilterPanel component for filtering product listings.
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```tsx
|
|
46
|
-
* import { ProductFilters, useProductAttributes } from '@rovela/sdk/products'
|
|
47
|
-
*
|
|
48
|
-
* function Sidebar() {
|
|
49
|
-
* const { attributes, priceRange } = useProductAttributes()
|
|
50
|
-
* const [filters, setFilters] = useState({
|
|
51
|
-
* categories: [],
|
|
52
|
-
* attributes: {},
|
|
53
|
-
* priceRange: {},
|
|
54
|
-
* })
|
|
55
|
-
*
|
|
56
|
-
* return (
|
|
57
|
-
* <ProductFilters
|
|
58
|
-
* attributes={attributes}
|
|
59
|
-
* priceRange={priceRange}
|
|
60
|
-
* values={filters}
|
|
61
|
-
* onChange={setFilters}
|
|
62
|
-
* collapsible
|
|
63
|
-
* showClearAll
|
|
64
|
-
* />
|
|
65
|
-
* )
|
|
66
|
-
* }
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export declare function ProductFilterPanel({ attributes, priceRange, categories, values, onChange, className, currency, locale, showCategories, showPriceFilter, collapsible, defaultExpanded, showClearAll, layout, }: ProductFilterPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
70
|
-
//# sourceMappingURL=ProductFilters.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProductFilters.d.ts","sourceRoot":"","sources":["../../../src/products/components/ProductFilters.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAMhD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACpC,UAAU,EAAE;QACV,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,GAAG,CAAC,EAAE,MAAM,CAAA;KACb,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,yCAAyC;IACzC,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC/B,mCAAmC;IACnC,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC9B,qCAAqC;IACrC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAA;IACvB,4BAA4B;IAC5B,MAAM,EAAE,mBAAmB,CAAA;IAC3B,mCAAmC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAC/C,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2BAA2B;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,wBAAwB;IACxB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,kCAAkC;IAClC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,4BAA4B;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uBAAuB;IACvB,MAAM,CAAC,EAAE,UAAU,GAAG,YAAY,CAAA;CACnC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,UAAe,EACf,UAAU,EACV,UAAe,EACf,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAgB,EAChB,MAAgB,EAChB,cAAqB,EACrB,eAAsB,EACtB,WAAkB,EAClB,eAAyC,EACzC,YAAmB,EACnB,MAAmB,GACpB,EAAE,uBAAuB,2CAqNzB"}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
/**
|
|
4
|
-
* @rovela/sdk/products/components/ProductFilters
|
|
5
|
-
*
|
|
6
|
-
* Comprehensive filter panel for product listings.
|
|
7
|
-
*/
|
|
8
|
-
import { useState, useCallback, useMemo } from 'react';
|
|
9
|
-
import { ChevronDown } from 'lucide-react';
|
|
10
|
-
import { cn, formatPrice } from '../../core/utils';
|
|
11
|
-
// =============================================================================
|
|
12
|
-
// Component
|
|
13
|
-
// =============================================================================
|
|
14
|
-
/**
|
|
15
|
-
* ProductFilterPanel component for filtering product listings.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* import { ProductFilters, useProductAttributes } from '@rovela/sdk/products'
|
|
20
|
-
*
|
|
21
|
-
* function Sidebar() {
|
|
22
|
-
* const { attributes, priceRange } = useProductAttributes()
|
|
23
|
-
* const [filters, setFilters] = useState({
|
|
24
|
-
* categories: [],
|
|
25
|
-
* attributes: {},
|
|
26
|
-
* priceRange: {},
|
|
27
|
-
* })
|
|
28
|
-
*
|
|
29
|
-
* return (
|
|
30
|
-
* <ProductFilters
|
|
31
|
-
* attributes={attributes}
|
|
32
|
-
* priceRange={priceRange}
|
|
33
|
-
* values={filters}
|
|
34
|
-
* onChange={setFilters}
|
|
35
|
-
* collapsible
|
|
36
|
-
* showClearAll
|
|
37
|
-
* />
|
|
38
|
-
* )
|
|
39
|
-
* }
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export function ProductFilterPanel({ attributes = [], priceRange, categories = [], values, onChange, className, currency = 'USD', locale = 'en-US', showCategories = true, showPriceFilter = true, collapsible = true, defaultExpanded = ['price', 'categories'], showClearAll = true, layout = 'vertical', }) {
|
|
43
|
-
const [expandedSections, setExpandedSections] = useState(new Set(defaultExpanded));
|
|
44
|
-
// Check if any filters are active
|
|
45
|
-
const hasActiveFilters = useMemo(() => {
|
|
46
|
-
return (values.categories.length > 0 ||
|
|
47
|
-
Object.values(values.attributes).some((v) => v.length > 0) ||
|
|
48
|
-
values.priceRange.min !== undefined ||
|
|
49
|
-
values.priceRange.max !== undefined);
|
|
50
|
-
}, [values]);
|
|
51
|
-
// Toggle section expansion
|
|
52
|
-
const toggleSection = useCallback((section) => {
|
|
53
|
-
setExpandedSections((prev) => {
|
|
54
|
-
const next = new Set(prev);
|
|
55
|
-
if (next.has(section)) {
|
|
56
|
-
next.delete(section);
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
next.add(section);
|
|
60
|
-
}
|
|
61
|
-
return next;
|
|
62
|
-
});
|
|
63
|
-
}, []);
|
|
64
|
-
// Handle category toggle
|
|
65
|
-
const handleCategoryToggle = useCallback((categoryId) => {
|
|
66
|
-
const newCategories = values.categories.includes(categoryId)
|
|
67
|
-
? values.categories.filter((id) => id !== categoryId)
|
|
68
|
-
: [...values.categories, categoryId];
|
|
69
|
-
onChange({ ...values, categories: newCategories });
|
|
70
|
-
}, [values, onChange]);
|
|
71
|
-
// Handle attribute toggle
|
|
72
|
-
const handleAttributeToggle = useCallback((attributeName, attributeValue) => {
|
|
73
|
-
const currentValues = values.attributes[attributeName] || [];
|
|
74
|
-
const newValues = currentValues.includes(attributeValue)
|
|
75
|
-
? currentValues.filter((v) => v !== attributeValue)
|
|
76
|
-
: [...currentValues, attributeValue];
|
|
77
|
-
onChange({
|
|
78
|
-
...values,
|
|
79
|
-
attributes: {
|
|
80
|
-
...values.attributes,
|
|
81
|
-
[attributeName]: newValues,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
}, [values, onChange]);
|
|
85
|
-
// Handle price range change
|
|
86
|
-
const handlePriceChange = useCallback((type, value) => {
|
|
87
|
-
onChange({
|
|
88
|
-
...values,
|
|
89
|
-
priceRange: {
|
|
90
|
-
...values.priceRange,
|
|
91
|
-
[type]: value,
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
}, [values, onChange]);
|
|
95
|
-
// Clear all filters
|
|
96
|
-
const handleClearAll = useCallback(() => {
|
|
97
|
-
onChange({
|
|
98
|
-
categories: [],
|
|
99
|
-
attributes: {},
|
|
100
|
-
priceRange: {},
|
|
101
|
-
});
|
|
102
|
-
}, [onChange]);
|
|
103
|
-
const containerClasses = cn(layout === 'vertical' ? 'space-y-4' : 'flex flex-wrap gap-4', className);
|
|
104
|
-
return (_jsxs("div", { className: containerClasses, children: [showClearAll && hasActiveFilters && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: "Filters" }), _jsx("button", { onClick: handleClearAll, className: "text-sm text-primary hover:underline", children: "Clear all" })] })), showCategories && categories.length > 0 && (_jsx(FilterSection, { title: "Category", sectionId: "categories", isExpanded: expandedSections.has('categories'), onToggle: collapsible ? () => toggleSection('categories') : undefined, layout: layout, children: _jsx("div", { className: "space-y-2", children: categories.map((category) => (_jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: values.categories.includes(category.id), onChange: () => handleCategoryToggle(category.id), className: "h-4 w-4 rounded border-border text-primary focus:ring-primary" }), _jsx("span", { className: "text-sm text-foreground", children: category.name })] }, category.id))) }) })), showPriceFilter && priceRange && (_jsx(FilterSection, { title: "Price", sectionId: "price", isExpanded: expandedSections.has('price'), onToggle: collapsible ? () => toggleSection('price') : undefined, layout: layout, children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "flex-1", children: [_jsx("label", { className: "sr-only", children: "Min price" }), _jsx("input", { type: "number", placeholder: formatPrice(priceRange.min, { currency, locale }), value: values.priceRange.min ?? '', onChange: (e) => handlePriceChange('min', e.target.value ? parseFloat(e.target.value) : undefined), min: 0, className: "w-full rounded-md border border-border bg-background px-3 py-1.5 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary" })] }), _jsx("span", { className: "text-muted-foreground", children: "to" }), _jsxs("div", { className: "flex-1", children: [_jsx("label", { className: "sr-only", children: "Max price" }), _jsx("input", { type: "number", placeholder: formatPrice(priceRange.max, { currency, locale }), value: values.priceRange.max ?? '', onChange: (e) => handlePriceChange('max', e.target.value ? parseFloat(e.target.value) : undefined), min: 0, className: "w-full rounded-md border border-border bg-background px-3 py-1.5 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary" })] })] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Range: ", formatPrice(priceRange.min, { currency, locale }), " -", ' ', formatPrice(priceRange.max, { currency, locale })] })] }) })), attributes.map((attribute) => (_jsx(FilterSection, { title: formatAttributeName(attribute.name), sectionId: attribute.name, isExpanded: expandedSections.has(attribute.name), onToggle: collapsible ? () => toggleSection(attribute.name) : undefined, layout: layout, children: _jsx("div", { className: "space-y-2", children: attribute.values.map((value) => (_jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: (values.attributes[attribute.name] || []).includes(value), onChange: () => handleAttributeToggle(attribute.name, value), className: "h-4 w-4 rounded border-border text-primary focus:ring-primary" }), _jsx("span", { className: "text-sm text-foreground", children: value })] }, value))) }) }, attribute.name)))] }));
|
|
105
|
-
}
|
|
106
|
-
function FilterSection({ title, sectionId, isExpanded, onToggle, children, layout = 'vertical', }) {
|
|
107
|
-
const isCollapsible = !!onToggle;
|
|
108
|
-
if (layout === 'horizontal') {
|
|
109
|
-
return (_jsxs("div", { className: "rounded-md border border-border p-3", children: [_jsx("span", { className: "mb-2 block text-sm font-medium text-foreground", children: title }), children] }));
|
|
110
|
-
}
|
|
111
|
-
return (_jsxs("div", { className: "border-b border-border pb-4", children: [isCollapsible ? (_jsxs("button", { onClick: onToggle, className: "flex w-full items-center justify-between py-2 text-sm font-medium text-foreground", "aria-expanded": isExpanded, "aria-controls": `filter-section-${sectionId}`, children: [_jsx("span", { children: title }), _jsx(ChevronDown, { className: cn('h-4 w-4 text-muted-foreground transition-transform', isExpanded && 'rotate-180') })] })) : (_jsx("span", { className: "block py-2 text-sm font-medium text-foreground", children: title })), (!isCollapsible || isExpanded) && (_jsx("div", { id: `filter-section-${sectionId}`, children: children }))] }));
|
|
112
|
-
}
|
|
113
|
-
// =============================================================================
|
|
114
|
-
// Helpers
|
|
115
|
-
// =============================================================================
|
|
116
|
-
function formatAttributeName(name) {
|
|
117
|
-
return name
|
|
118
|
-
.replace(/_/g, ' ')
|
|
119
|
-
.replace(/([A-Z])/g, ' $1')
|
|
120
|
-
.trim()
|
|
121
|
-
.split(' ')
|
|
122
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
123
|
-
.join(' ');
|
|
124
|
-
}
|
|
125
|
-
//# sourceMappingURL=ProductFilters.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProductFilters.js","sourceRoot":"","sources":["../../../src/products/components/ProductFilters.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { Category } from '../../core/types';
|
|
2
|
-
export interface CategoryWithChildren extends Category {
|
|
3
|
-
children: CategoryWithChildren[];
|
|
4
|
-
}
|
|
5
|
-
export interface UseCategoriesOptions {
|
|
6
|
-
/** API endpoint (default /api/categories) */
|
|
7
|
-
endpoint?: string;
|
|
8
|
-
/** Skip fetching */
|
|
9
|
-
skip?: boolean;
|
|
10
|
-
/** Initial data (for SSR hydration) */
|
|
11
|
-
initialData?: Category[];
|
|
12
|
-
}
|
|
13
|
-
export interface UseCategoriesReturn {
|
|
14
|
-
/** Flat list of all categories */
|
|
15
|
-
categories: Category[];
|
|
16
|
-
/** Hierarchical category tree (root categories with nested children) */
|
|
17
|
-
tree: CategoryWithChildren[];
|
|
18
|
-
/** Whether data is currently loading */
|
|
19
|
-
isLoading: boolean;
|
|
20
|
-
/** Error if request failed */
|
|
21
|
-
error: Error | null;
|
|
22
|
-
/** Refresh the categories */
|
|
23
|
-
refresh: () => void;
|
|
24
|
-
/** Get a category by ID */
|
|
25
|
-
getCategoryById: (id: string) => Category | undefined;
|
|
26
|
-
/** Get a category by slug */
|
|
27
|
-
getCategoryBySlug: (slug: string) => Category | undefined;
|
|
28
|
-
/** Get child categories of a parent */
|
|
29
|
-
getChildren: (parentId: string | null) => Category[];
|
|
30
|
-
/** Get breadcrumb path for a category */
|
|
31
|
-
getBreadcrumb: (categoryId: string) => Category[];
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Hook for fetching and managing categories.
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* ```tsx
|
|
38
|
-
* import { useCategories } from '@rovela/sdk/products'
|
|
39
|
-
*
|
|
40
|
-
* function CategoryNav() {
|
|
41
|
-
* const { tree, isLoading } = useCategories()
|
|
42
|
-
*
|
|
43
|
-
* if (isLoading) return <div>Loading...</div>
|
|
44
|
-
*
|
|
45
|
-
* return (
|
|
46
|
-
* <nav>
|
|
47
|
-
* {tree.map(category => (
|
|
48
|
-
* <CategoryLink key={category.id} category={category} />
|
|
49
|
-
* ))}
|
|
50
|
-
* </nav>
|
|
51
|
-
* )
|
|
52
|
-
* }
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
export declare function useCategories(options?: UseCategoriesOptions): UseCategoriesReturn;
|
|
56
|
-
//# sourceMappingURL=useCategories.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useCategories.d.ts","sourceRoot":"","sources":["../../../src/products/hooks/useCategories.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAMhD,MAAM,WAAW,oBAAqB,SAAQ,QAAQ;IACpD,QAAQ,EAAE,oBAAoB,EAAE,CAAA;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oBAAoB;IACpB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uCAAuC;IACvC,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,kCAAkC;IAClC,UAAU,EAAE,QAAQ,EAAE,CAAA;IACtB,wEAAwE;IACxE,IAAI,EAAE,oBAAoB,EAAE,CAAA;IAC5B,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,8BAA8B;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,2BAA2B;IAC3B,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAA;IACrD,6BAA6B;IAC7B,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAA;IACzD,uCAAuC;IACvC,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,QAAQ,EAAE,CAAA;IACpD,yCAAyC;IACzC,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAA;CAClD;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA+HrB"}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
/**
|
|
3
|
-
* @rovela/sdk/products/hooks/useCategories
|
|
4
|
-
*
|
|
5
|
-
* Hook for fetching category tree.
|
|
6
|
-
*/
|
|
7
|
-
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
8
|
-
// =============================================================================
|
|
9
|
-
// Hook
|
|
10
|
-
// =============================================================================
|
|
11
|
-
/**
|
|
12
|
-
* Hook for fetching and managing categories.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```tsx
|
|
16
|
-
* import { useCategories } from '@rovela/sdk/products'
|
|
17
|
-
*
|
|
18
|
-
* function CategoryNav() {
|
|
19
|
-
* const { tree, isLoading } = useCategories()
|
|
20
|
-
*
|
|
21
|
-
* if (isLoading) return <div>Loading...</div>
|
|
22
|
-
*
|
|
23
|
-
* return (
|
|
24
|
-
* <nav>
|
|
25
|
-
* {tree.map(category => (
|
|
26
|
-
* <CategoryLink key={category.id} category={category} />
|
|
27
|
-
* ))}
|
|
28
|
-
* </nav>
|
|
29
|
-
* )
|
|
30
|
-
* }
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export function useCategories(options = {}) {
|
|
34
|
-
const { endpoint = '/api/categories', skip = false, initialData, } = options;
|
|
35
|
-
const [categories, setCategories] = useState(initialData || []);
|
|
36
|
-
const [isLoading, setIsLoading] = useState(!initialData && !skip);
|
|
37
|
-
const [error, setError] = useState(null);
|
|
38
|
-
// Fetch categories
|
|
39
|
-
const fetchCategories = useCallback(async () => {
|
|
40
|
-
if (skip)
|
|
41
|
-
return;
|
|
42
|
-
setIsLoading(true);
|
|
43
|
-
setError(null);
|
|
44
|
-
try {
|
|
45
|
-
const response = await fetch(endpoint);
|
|
46
|
-
if (!response.ok) {
|
|
47
|
-
const errorData = await response.json().catch(() => ({}));
|
|
48
|
-
throw new Error(errorData.error || `HTTP ${response.status}`);
|
|
49
|
-
}
|
|
50
|
-
const data = await response.json();
|
|
51
|
-
setCategories(data.data || []);
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
setError(err instanceof Error ? err : new Error('Failed to fetch categories'));
|
|
55
|
-
}
|
|
56
|
-
finally {
|
|
57
|
-
setIsLoading(false);
|
|
58
|
-
}
|
|
59
|
-
}, [endpoint, skip]);
|
|
60
|
-
// Fetch on mount and when fetchCategories' captured endpoint changes.
|
|
61
|
-
// initialData is read once on mount as a hydration shortcut — listing it
|
|
62
|
-
// would re-fetch every time a parent passes a new SSR snapshot.
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
if (!initialData) {
|
|
65
|
-
fetchCategories();
|
|
66
|
-
}
|
|
67
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
-
}, [fetchCategories]);
|
|
69
|
-
// Build category tree
|
|
70
|
-
const tree = useMemo(() => {
|
|
71
|
-
const categoryMap = new Map();
|
|
72
|
-
// First pass: create all nodes with empty children
|
|
73
|
-
categories.forEach((cat) => {
|
|
74
|
-
categoryMap.set(cat.id, { ...cat, children: [] });
|
|
75
|
-
});
|
|
76
|
-
// Second pass: build tree structure
|
|
77
|
-
const roots = [];
|
|
78
|
-
categories.forEach((cat) => {
|
|
79
|
-
const node = categoryMap.get(cat.id);
|
|
80
|
-
if (cat.parentId && categoryMap.has(cat.parentId)) {
|
|
81
|
-
const parent = categoryMap.get(cat.parentId);
|
|
82
|
-
parent.children.push(node);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
roots.push(node);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
// Sort children by order
|
|
89
|
-
const sortChildren = (nodes) => {
|
|
90
|
-
nodes.sort((a, b) => a.order - b.order);
|
|
91
|
-
nodes.forEach((node) => sortChildren(node.children));
|
|
92
|
-
};
|
|
93
|
-
sortChildren(roots);
|
|
94
|
-
return roots;
|
|
95
|
-
}, [categories]);
|
|
96
|
-
// Helper: get category by ID
|
|
97
|
-
const getCategoryById = useCallback((id) => categories.find((c) => c.id === id), [categories]);
|
|
98
|
-
// Helper: get category by slug
|
|
99
|
-
const getCategoryBySlug = useCallback((slug) => categories.find((c) => c.slug === slug), [categories]);
|
|
100
|
-
// Helper: get children of a parent
|
|
101
|
-
const getChildren = useCallback((parentId) => categories
|
|
102
|
-
.filter((c) => c.parentId === parentId)
|
|
103
|
-
.sort((a, b) => a.order - b.order), [categories]);
|
|
104
|
-
// Helper: get breadcrumb path
|
|
105
|
-
const getBreadcrumb = useCallback((categoryId) => {
|
|
106
|
-
const path = [];
|
|
107
|
-
let current = getCategoryById(categoryId);
|
|
108
|
-
while (current) {
|
|
109
|
-
path.unshift(current);
|
|
110
|
-
current = current.parentId ? getCategoryById(current.parentId) : undefined;
|
|
111
|
-
}
|
|
112
|
-
return path;
|
|
113
|
-
}, [getCategoryById]);
|
|
114
|
-
return {
|
|
115
|
-
categories,
|
|
116
|
-
tree,
|
|
117
|
-
isLoading,
|
|
118
|
-
error,
|
|
119
|
-
refresh: fetchCategories,
|
|
120
|
-
getCategoryById,
|
|
121
|
-
getCategoryBySlug,
|
|
122
|
-
getChildren,
|
|
123
|
-
getBreadcrumb,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
//# sourceMappingURL=useCategories.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useCategories.js","sourceRoot":"","sources":["../../../src/products/hooks/useCategories.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
export interface ProductAttribute {
|
|
2
|
-
/** Attribute name (e.g., "color", "size") */
|
|
3
|
-
name: string;
|
|
4
|
-
/** All unique values for this attribute */
|
|
5
|
-
values: string[];
|
|
6
|
-
}
|
|
7
|
-
export interface PriceRange {
|
|
8
|
-
min: number;
|
|
9
|
-
max: number;
|
|
10
|
-
}
|
|
11
|
-
export interface UseProductAttributesOptions {
|
|
12
|
-
/** Category to filter by (fetches products from this category) */
|
|
13
|
-
categoryId?: string;
|
|
14
|
-
/** API endpoint for products */
|
|
15
|
-
endpoint?: string;
|
|
16
|
-
/** Skip fetching */
|
|
17
|
-
skip?: boolean;
|
|
18
|
-
}
|
|
19
|
-
export interface UseProductAttributesReturn {
|
|
20
|
-
/** Available filter attributes with their values */
|
|
21
|
-
attributes: ProductAttribute[];
|
|
22
|
-
/** Price range across all products */
|
|
23
|
-
priceRange: PriceRange | null;
|
|
24
|
-
/** Whether data is currently loading */
|
|
25
|
-
isLoading: boolean;
|
|
26
|
-
/** Error if request failed */
|
|
27
|
-
error: Error | null;
|
|
28
|
-
/** Refresh the attributes */
|
|
29
|
-
refresh: () => void;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Hook for extracting available product attributes for filtering.
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```tsx
|
|
36
|
-
* import { useProductAttributes } from '@rovela/sdk/products'
|
|
37
|
-
*
|
|
38
|
-
* function ProductFilters({ categoryId }: { categoryId?: string }) {
|
|
39
|
-
* const { attributes, priceRange, isLoading } = useProductAttributes({
|
|
40
|
-
* categoryId,
|
|
41
|
-
* })
|
|
42
|
-
*
|
|
43
|
-
* if (isLoading) return <div>Loading filters...</div>
|
|
44
|
-
*
|
|
45
|
-
* return (
|
|
46
|
-
* <div>
|
|
47
|
-
* {attributes.map(attr => (
|
|
48
|
-
* <FilterGroup key={attr.name} name={attr.name} values={attr.values} />
|
|
49
|
-
* ))}
|
|
50
|
-
* {priceRange && (
|
|
51
|
-
* <PriceSlider min={priceRange.min} max={priceRange.max} />
|
|
52
|
-
* )}
|
|
53
|
-
* </div>
|
|
54
|
-
* )
|
|
55
|
-
* }
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
export declare function useProductAttributes(options?: UseProductAttributesOptions): UseProductAttributesReturn;
|
|
59
|
-
//# sourceMappingURL=useProductAttributes.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useProductAttributes.d.ts","sourceRoot":"","sources":["../../../src/products/hooks/useProductAttributes.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,2BAA2B;IAC1C,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oBAAoB;IACpB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,oDAAoD;IACpD,UAAU,EAAE,gBAAgB,EAAE,CAAA;IAC9B,sCAAsC;IACtC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7B,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,8BAA8B;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,2BAAgC,GACxC,0BAA0B,CAmG5B"}
|