@amboras-dev/engraving 0.2.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.mts +169 -0
- package/dist/index.d.ts +169 -0
- package/dist/index.js +205 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +167 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +36 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
|
+
|
|
3
|
+
type EngravingElementType = 'text' | 'monogram' | 'dropdown' | 'buttons' | 'swatch' | 'checkbox';
|
|
4
|
+
interface EngravingOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
swatch?: string;
|
|
8
|
+
}
|
|
9
|
+
type EngravingConditionOperator = 'equals' | 'not_equals' | 'exists' | 'not_exists';
|
|
10
|
+
interface EngravingConditionRule {
|
|
11
|
+
elementId: string;
|
|
12
|
+
operator?: EngravingConditionOperator;
|
|
13
|
+
value?: string;
|
|
14
|
+
/** @deprecated legacy shorthand — read as { operator: 'equals', value: equals } */
|
|
15
|
+
equals?: string;
|
|
16
|
+
}
|
|
17
|
+
interface EngravingConditions {
|
|
18
|
+
/** 'all' = AND across rules, 'any' = OR */
|
|
19
|
+
logic: 'all' | 'any';
|
|
20
|
+
rules: EngravingConditionRule[];
|
|
21
|
+
}
|
|
22
|
+
interface EngravingPreviewPlacement {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
fontSize?: number;
|
|
26
|
+
fontFamily?: string;
|
|
27
|
+
letterSpacing?: number;
|
|
28
|
+
color?: string;
|
|
29
|
+
align?: 'left' | 'center' | 'right';
|
|
30
|
+
rotation?: number;
|
|
31
|
+
/** Curved/circular text: total arc angle in degrees. 0 = straight. */
|
|
32
|
+
curve?: number;
|
|
33
|
+
}
|
|
34
|
+
interface EngravingElement {
|
|
35
|
+
id: string;
|
|
36
|
+
type: EngravingElementType;
|
|
37
|
+
label: string;
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
helpText?: string;
|
|
40
|
+
required?: boolean;
|
|
41
|
+
maxLength?: number;
|
|
42
|
+
options?: EngravingOption[];
|
|
43
|
+
conditions?: EngravingConditions;
|
|
44
|
+
preview?: EngravingPreviewPlacement;
|
|
45
|
+
}
|
|
46
|
+
interface EngravingTemplate {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
status: 'active' | 'draft';
|
|
50
|
+
/** merchant-entered fee in the store's default currency, minor units */
|
|
51
|
+
default_fee?: number;
|
|
52
|
+
/** per-currency fee map (minor units) */
|
|
53
|
+
fee: Record<string, number>;
|
|
54
|
+
elements: EngravingElement[];
|
|
55
|
+
/**
|
|
56
|
+
* Customer-selectable font families (CSS values). When non-empty, the drawer
|
|
57
|
+
* shows a font picker and the chosen font overrides each text element's
|
|
58
|
+
* preview font. Empty/absent = no picker.
|
|
59
|
+
*/
|
|
60
|
+
fonts?: string[];
|
|
61
|
+
background?: {
|
|
62
|
+
source: 'product_image' | 'custom';
|
|
63
|
+
url?: string;
|
|
64
|
+
};
|
|
65
|
+
/** preview coordinate space (element x/y are in these units); default 800x800 */
|
|
66
|
+
canvas?: {
|
|
67
|
+
width: number;
|
|
68
|
+
height: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
interface EngravingConfig {
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
templates: EngravingTemplate[];
|
|
74
|
+
}
|
|
75
|
+
interface EngravingVariant {
|
|
76
|
+
id: string;
|
|
77
|
+
title?: string;
|
|
78
|
+
calculated_price?: {
|
|
79
|
+
calculated_amount?: number;
|
|
80
|
+
currency_code?: string;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
interface EngravingProduct {
|
|
84
|
+
id: string;
|
|
85
|
+
title?: string;
|
|
86
|
+
thumbnail?: string | null;
|
|
87
|
+
images?: Array<{
|
|
88
|
+
url: string;
|
|
89
|
+
}>;
|
|
90
|
+
metadata?: Record<string, unknown> | null;
|
|
91
|
+
variants?: EngravingVariant[];
|
|
92
|
+
}
|
|
93
|
+
/** Field values keyed by element id. */
|
|
94
|
+
type EngravingFieldValues = Record<string, string>;
|
|
95
|
+
interface AddEngravingInput {
|
|
96
|
+
variant_id: string;
|
|
97
|
+
quantity?: number;
|
|
98
|
+
template_id: string;
|
|
99
|
+
fields: EngravingFieldValues;
|
|
100
|
+
preview_url?: string;
|
|
101
|
+
/** Customer-chosen font (validated server-side against template.fonts). */
|
|
102
|
+
font?: string;
|
|
103
|
+
}
|
|
104
|
+
interface AddEngravingResult {
|
|
105
|
+
ok: boolean;
|
|
106
|
+
error?: string;
|
|
107
|
+
}
|
|
108
|
+
/** Resolved engraving context for a product (config + product + its template). */
|
|
109
|
+
interface ResolvedEngraving {
|
|
110
|
+
template: EngravingTemplate;
|
|
111
|
+
product: EngravingProduct;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolves whether a product can be engraved: engraving must be enabled on the
|
|
116
|
+
* store AND the product must carry `metadata.engraving_template_id` pointing at
|
|
117
|
+
* an active template. Returns null when engraving shouldn't show for this
|
|
118
|
+
* product, so the storefront button can simply render nothing.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* const { data } = useEngraving(product.id)
|
|
122
|
+
* if (!data) return null
|
|
123
|
+
* // data.template, data.product
|
|
124
|
+
*/
|
|
125
|
+
declare function useEngraving(productId: string): _tanstack_react_query.UseQueryResult<ResolvedEngraving | null, Error>;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Live engraving fee for a template in a given currency, resolved server-side
|
|
129
|
+
* from the store's locked FX rate (so it covers every supported currency and
|
|
130
|
+
* matches exactly what the add-to-cart route charges). Returns `undefined`
|
|
131
|
+
* while loading and `null` when the currency is unsupported.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* const { data: fee, isLoading } = useEngravingFee(template.id, cart.currency_code)
|
|
135
|
+
*/
|
|
136
|
+
declare function useEngravingFee(templateId: string, currency: string): _tanstack_react_query.UseQueryResult<number | null, Error>;
|
|
137
|
+
|
|
138
|
+
/** Public store headers — publishable key + (optional) multi-tenant env id. */
|
|
139
|
+
declare function storeHeaders(extra?: Record<string, string>): Record<string, string>;
|
|
140
|
+
/** Reads store.metadata.plugins.engraving via the public integrations endpoint. */
|
|
141
|
+
declare function fetchEngravingConfig(): Promise<EngravingConfig | null>;
|
|
142
|
+
/** First region id — used for pricing context when no cart region is known yet. */
|
|
143
|
+
declare function fetchRegionId(): Promise<string | null>;
|
|
144
|
+
/** Product with metadata, images and per-variant calculated price in a region. */
|
|
145
|
+
declare function fetchEngravingProduct(productId: string, regionId: string): Promise<EngravingProduct | null>;
|
|
146
|
+
/**
|
|
147
|
+
* Live per-currency fee, resolved server-side from the store's locked FX rate.
|
|
148
|
+
* Covers every currency the store supports — not just the ones in the template's
|
|
149
|
+
* stored fee map (which can go stale when a currency is added later). Returns
|
|
150
|
+
* null when the currency is genuinely unsupported.
|
|
151
|
+
*/
|
|
152
|
+
declare function fetchEngravingFee(templateId: string, currency: string): Promise<number | null>;
|
|
153
|
+
/**
|
|
154
|
+
* Add an engraved line to a cart. The server reprices the line to base + the
|
|
155
|
+
* per-currency engraving fee and snapshots the selection on the line metadata.
|
|
156
|
+
*/
|
|
157
|
+
declare function addEngravingLine(cartId: string, input: AddEngravingInput): Promise<AddEngravingResult>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Conditional show/hide for an engraving field — mirrors the admin builder and
|
|
161
|
+
* the Medusa server-side validation so the storefront, preview and server agree.
|
|
162
|
+
*/
|
|
163
|
+
declare function isElementVisible(el: EngravingElement, values: EngravingFieldValues): boolean;
|
|
164
|
+
/** Format a minor-unit amount as currency (e.g. 1000, 'sgd' → "SGD 10.00"). */
|
|
165
|
+
declare function formatMoney(amountCents: number, currency: string): string;
|
|
166
|
+
declare function variantPrice(v?: EngravingVariant): number | undefined;
|
|
167
|
+
declare function variantCurrency(v?: EngravingVariant): string;
|
|
168
|
+
|
|
169
|
+
export { type AddEngravingInput, type AddEngravingResult, type EngravingConditionOperator, type EngravingConditionRule, type EngravingConditions, type EngravingConfig, type EngravingElement, type EngravingElementType, type EngravingFieldValues, type EngravingOption, type EngravingPreviewPlacement, type EngravingProduct, type EngravingTemplate, type EngravingVariant, type ResolvedEngraving, addEngravingLine, fetchEngravingConfig, fetchEngravingFee, fetchEngravingProduct, fetchRegionId, formatMoney, isElementVisible, storeHeaders, useEngraving, useEngravingFee, variantCurrency, variantPrice };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
|
+
|
|
3
|
+
type EngravingElementType = 'text' | 'monogram' | 'dropdown' | 'buttons' | 'swatch' | 'checkbox';
|
|
4
|
+
interface EngravingOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
swatch?: string;
|
|
8
|
+
}
|
|
9
|
+
type EngravingConditionOperator = 'equals' | 'not_equals' | 'exists' | 'not_exists';
|
|
10
|
+
interface EngravingConditionRule {
|
|
11
|
+
elementId: string;
|
|
12
|
+
operator?: EngravingConditionOperator;
|
|
13
|
+
value?: string;
|
|
14
|
+
/** @deprecated legacy shorthand — read as { operator: 'equals', value: equals } */
|
|
15
|
+
equals?: string;
|
|
16
|
+
}
|
|
17
|
+
interface EngravingConditions {
|
|
18
|
+
/** 'all' = AND across rules, 'any' = OR */
|
|
19
|
+
logic: 'all' | 'any';
|
|
20
|
+
rules: EngravingConditionRule[];
|
|
21
|
+
}
|
|
22
|
+
interface EngravingPreviewPlacement {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
fontSize?: number;
|
|
26
|
+
fontFamily?: string;
|
|
27
|
+
letterSpacing?: number;
|
|
28
|
+
color?: string;
|
|
29
|
+
align?: 'left' | 'center' | 'right';
|
|
30
|
+
rotation?: number;
|
|
31
|
+
/** Curved/circular text: total arc angle in degrees. 0 = straight. */
|
|
32
|
+
curve?: number;
|
|
33
|
+
}
|
|
34
|
+
interface EngravingElement {
|
|
35
|
+
id: string;
|
|
36
|
+
type: EngravingElementType;
|
|
37
|
+
label: string;
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
helpText?: string;
|
|
40
|
+
required?: boolean;
|
|
41
|
+
maxLength?: number;
|
|
42
|
+
options?: EngravingOption[];
|
|
43
|
+
conditions?: EngravingConditions;
|
|
44
|
+
preview?: EngravingPreviewPlacement;
|
|
45
|
+
}
|
|
46
|
+
interface EngravingTemplate {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
status: 'active' | 'draft';
|
|
50
|
+
/** merchant-entered fee in the store's default currency, minor units */
|
|
51
|
+
default_fee?: number;
|
|
52
|
+
/** per-currency fee map (minor units) */
|
|
53
|
+
fee: Record<string, number>;
|
|
54
|
+
elements: EngravingElement[];
|
|
55
|
+
/**
|
|
56
|
+
* Customer-selectable font families (CSS values). When non-empty, the drawer
|
|
57
|
+
* shows a font picker and the chosen font overrides each text element's
|
|
58
|
+
* preview font. Empty/absent = no picker.
|
|
59
|
+
*/
|
|
60
|
+
fonts?: string[];
|
|
61
|
+
background?: {
|
|
62
|
+
source: 'product_image' | 'custom';
|
|
63
|
+
url?: string;
|
|
64
|
+
};
|
|
65
|
+
/** preview coordinate space (element x/y are in these units); default 800x800 */
|
|
66
|
+
canvas?: {
|
|
67
|
+
width: number;
|
|
68
|
+
height: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
interface EngravingConfig {
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
templates: EngravingTemplate[];
|
|
74
|
+
}
|
|
75
|
+
interface EngravingVariant {
|
|
76
|
+
id: string;
|
|
77
|
+
title?: string;
|
|
78
|
+
calculated_price?: {
|
|
79
|
+
calculated_amount?: number;
|
|
80
|
+
currency_code?: string;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
interface EngravingProduct {
|
|
84
|
+
id: string;
|
|
85
|
+
title?: string;
|
|
86
|
+
thumbnail?: string | null;
|
|
87
|
+
images?: Array<{
|
|
88
|
+
url: string;
|
|
89
|
+
}>;
|
|
90
|
+
metadata?: Record<string, unknown> | null;
|
|
91
|
+
variants?: EngravingVariant[];
|
|
92
|
+
}
|
|
93
|
+
/** Field values keyed by element id. */
|
|
94
|
+
type EngravingFieldValues = Record<string, string>;
|
|
95
|
+
interface AddEngravingInput {
|
|
96
|
+
variant_id: string;
|
|
97
|
+
quantity?: number;
|
|
98
|
+
template_id: string;
|
|
99
|
+
fields: EngravingFieldValues;
|
|
100
|
+
preview_url?: string;
|
|
101
|
+
/** Customer-chosen font (validated server-side against template.fonts). */
|
|
102
|
+
font?: string;
|
|
103
|
+
}
|
|
104
|
+
interface AddEngravingResult {
|
|
105
|
+
ok: boolean;
|
|
106
|
+
error?: string;
|
|
107
|
+
}
|
|
108
|
+
/** Resolved engraving context for a product (config + product + its template). */
|
|
109
|
+
interface ResolvedEngraving {
|
|
110
|
+
template: EngravingTemplate;
|
|
111
|
+
product: EngravingProduct;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolves whether a product can be engraved: engraving must be enabled on the
|
|
116
|
+
* store AND the product must carry `metadata.engraving_template_id` pointing at
|
|
117
|
+
* an active template. Returns null when engraving shouldn't show for this
|
|
118
|
+
* product, so the storefront button can simply render nothing.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* const { data } = useEngraving(product.id)
|
|
122
|
+
* if (!data) return null
|
|
123
|
+
* // data.template, data.product
|
|
124
|
+
*/
|
|
125
|
+
declare function useEngraving(productId: string): _tanstack_react_query.UseQueryResult<ResolvedEngraving | null, Error>;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Live engraving fee for a template in a given currency, resolved server-side
|
|
129
|
+
* from the store's locked FX rate (so it covers every supported currency and
|
|
130
|
+
* matches exactly what the add-to-cart route charges). Returns `undefined`
|
|
131
|
+
* while loading and `null` when the currency is unsupported.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* const { data: fee, isLoading } = useEngravingFee(template.id, cart.currency_code)
|
|
135
|
+
*/
|
|
136
|
+
declare function useEngravingFee(templateId: string, currency: string): _tanstack_react_query.UseQueryResult<number | null, Error>;
|
|
137
|
+
|
|
138
|
+
/** Public store headers — publishable key + (optional) multi-tenant env id. */
|
|
139
|
+
declare function storeHeaders(extra?: Record<string, string>): Record<string, string>;
|
|
140
|
+
/** Reads store.metadata.plugins.engraving via the public integrations endpoint. */
|
|
141
|
+
declare function fetchEngravingConfig(): Promise<EngravingConfig | null>;
|
|
142
|
+
/** First region id — used for pricing context when no cart region is known yet. */
|
|
143
|
+
declare function fetchRegionId(): Promise<string | null>;
|
|
144
|
+
/** Product with metadata, images and per-variant calculated price in a region. */
|
|
145
|
+
declare function fetchEngravingProduct(productId: string, regionId: string): Promise<EngravingProduct | null>;
|
|
146
|
+
/**
|
|
147
|
+
* Live per-currency fee, resolved server-side from the store's locked FX rate.
|
|
148
|
+
* Covers every currency the store supports — not just the ones in the template's
|
|
149
|
+
* stored fee map (which can go stale when a currency is added later). Returns
|
|
150
|
+
* null when the currency is genuinely unsupported.
|
|
151
|
+
*/
|
|
152
|
+
declare function fetchEngravingFee(templateId: string, currency: string): Promise<number | null>;
|
|
153
|
+
/**
|
|
154
|
+
* Add an engraved line to a cart. The server reprices the line to base + the
|
|
155
|
+
* per-currency engraving fee and snapshots the selection on the line metadata.
|
|
156
|
+
*/
|
|
157
|
+
declare function addEngravingLine(cartId: string, input: AddEngravingInput): Promise<AddEngravingResult>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Conditional show/hide for an engraving field — mirrors the admin builder and
|
|
161
|
+
* the Medusa server-side validation so the storefront, preview and server agree.
|
|
162
|
+
*/
|
|
163
|
+
declare function isElementVisible(el: EngravingElement, values: EngravingFieldValues): boolean;
|
|
164
|
+
/** Format a minor-unit amount as currency (e.g. 1000, 'sgd' → "SGD 10.00"). */
|
|
165
|
+
declare function formatMoney(amountCents: number, currency: string): string;
|
|
166
|
+
declare function variantPrice(v?: EngravingVariant): number | undefined;
|
|
167
|
+
declare function variantCurrency(v?: EngravingVariant): string;
|
|
168
|
+
|
|
169
|
+
export { type AddEngravingInput, type AddEngravingResult, type EngravingConditionOperator, type EngravingConditionRule, type EngravingConditions, type EngravingConfig, type EngravingElement, type EngravingElementType, type EngravingFieldValues, type EngravingOption, type EngravingPreviewPlacement, type EngravingProduct, type EngravingTemplate, type EngravingVariant, type ResolvedEngraving, addEngravingLine, fetchEngravingConfig, fetchEngravingFee, fetchEngravingProduct, fetchRegionId, formatMoney, isElementVisible, storeHeaders, useEngraving, useEngravingFee, variantCurrency, variantPrice };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
addEngravingLine: () => addEngravingLine,
|
|
24
|
+
fetchEngravingConfig: () => fetchEngravingConfig,
|
|
25
|
+
fetchEngravingFee: () => fetchEngravingFee,
|
|
26
|
+
fetchEngravingProduct: () => fetchEngravingProduct,
|
|
27
|
+
fetchRegionId: () => fetchRegionId,
|
|
28
|
+
formatMoney: () => formatMoney,
|
|
29
|
+
isElementVisible: () => isElementVisible,
|
|
30
|
+
storeHeaders: () => storeHeaders,
|
|
31
|
+
useEngraving: () => useEngraving,
|
|
32
|
+
useEngravingFee: () => useEngravingFee,
|
|
33
|
+
variantCurrency: () => variantCurrency,
|
|
34
|
+
variantPrice: () => variantPrice
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/hooks/use-engraving.ts
|
|
39
|
+
var import_react_query = require("@tanstack/react-query");
|
|
40
|
+
|
|
41
|
+
// src/lib/fetch.ts
|
|
42
|
+
function resolveEnv(key) {
|
|
43
|
+
if (key === "NEXT_PUBLIC_MEDUSA_BACKEND_URL") return process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL;
|
|
44
|
+
if (key === "NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY") return process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY;
|
|
45
|
+
if (key === "NEXT_PUBLIC_STORE_ID") return process.env.NEXT_PUBLIC_STORE_ID;
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
function baseUrl() {
|
|
49
|
+
return resolveEnv("NEXT_PUBLIC_MEDUSA_BACKEND_URL") ?? "http://localhost:9000";
|
|
50
|
+
}
|
|
51
|
+
function storeHeaders(extra) {
|
|
52
|
+
const headers = { ...extra ?? {} };
|
|
53
|
+
const key = resolveEnv("NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY");
|
|
54
|
+
const storeId = resolveEnv("NEXT_PUBLIC_STORE_ID");
|
|
55
|
+
if (key) headers["x-publishable-api-key"] = key;
|
|
56
|
+
if (storeId) headers["x-store-environment-id"] = storeId;
|
|
57
|
+
return headers;
|
|
58
|
+
}
|
|
59
|
+
async function fetchEngravingConfig() {
|
|
60
|
+
try {
|
|
61
|
+
const res = await fetch(`${baseUrl()}/store/integrations/active`, { headers: storeHeaders() });
|
|
62
|
+
if (!res.ok) return null;
|
|
63
|
+
const data = await res.json();
|
|
64
|
+
return data && data.engraving || null;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function fetchRegionId() {
|
|
70
|
+
try {
|
|
71
|
+
const res = await fetch(`${baseUrl()}/store/regions`, { headers: storeHeaders() });
|
|
72
|
+
if (!res.ok) return null;
|
|
73
|
+
const data = await res.json();
|
|
74
|
+
return data.regions && data.regions[0] && data.regions[0].id || null;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function fetchEngravingProduct(productId, regionId) {
|
|
80
|
+
try {
|
|
81
|
+
const fields = "id,title,thumbnail,metadata,*images,*variants,*variants.calculated_price";
|
|
82
|
+
const url = `${baseUrl()}/store/products/${productId}?region_id=${encodeURIComponent(regionId)}&fields=${encodeURIComponent(fields)}`;
|
|
83
|
+
const res = await fetch(url, { headers: storeHeaders() });
|
|
84
|
+
if (!res.ok) return null;
|
|
85
|
+
const data = await res.json();
|
|
86
|
+
return data.product || null;
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function fetchEngravingFee(templateId, currency) {
|
|
92
|
+
try {
|
|
93
|
+
const url = `${baseUrl()}/store/engraving/fee?template_id=${encodeURIComponent(templateId)}¤cy=${encodeURIComponent(currency)}`;
|
|
94
|
+
const res = await fetch(url, { headers: storeHeaders() });
|
|
95
|
+
if (!res.ok) return null;
|
|
96
|
+
const data = await res.json();
|
|
97
|
+
return typeof data.fee === "number" ? data.fee : null;
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function addEngravingLine(cartId, input) {
|
|
103
|
+
try {
|
|
104
|
+
const res = await fetch(`${baseUrl()}/store/carts/${cartId}/line-items-engraving`, {
|
|
105
|
+
method: "POST",
|
|
106
|
+
headers: storeHeaders({ "Content-Type": "application/json" }),
|
|
107
|
+
body: JSON.stringify(input)
|
|
108
|
+
});
|
|
109
|
+
if (res.ok) return { ok: true };
|
|
110
|
+
const data = await res.json().catch(() => ({}));
|
|
111
|
+
const error = data.errors && data.errors.join("; ") || data.error || data.message || `Could not add engraving (${res.status})`;
|
|
112
|
+
return { ok: false, error };
|
|
113
|
+
} catch (e) {
|
|
114
|
+
return { ok: false, error: e instanceof Error ? e.message : "Network error" };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/hooks/use-engraving.ts
|
|
119
|
+
function useEngraving(productId) {
|
|
120
|
+
return (0, import_react_query.useQuery)({
|
|
121
|
+
queryKey: ["engraving-pdp", productId],
|
|
122
|
+
queryFn: async () => {
|
|
123
|
+
const config = await fetchEngravingConfig();
|
|
124
|
+
if (!config || !config.enabled) return null;
|
|
125
|
+
const regionId = await fetchRegionId();
|
|
126
|
+
if (!regionId) return null;
|
|
127
|
+
const product = await fetchEngravingProduct(productId, regionId);
|
|
128
|
+
if (!product) return null;
|
|
129
|
+
const templateId = product.metadata && product.metadata.engraving_template_id;
|
|
130
|
+
if (!templateId) return null;
|
|
131
|
+
const template = (config.templates || []).find(
|
|
132
|
+
(t) => t.id === templateId && t.status === "active"
|
|
133
|
+
);
|
|
134
|
+
if (!template) return null;
|
|
135
|
+
return { template, product };
|
|
136
|
+
},
|
|
137
|
+
staleTime: 1e3 * 60,
|
|
138
|
+
// 1 minute
|
|
139
|
+
enabled: !!productId
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/hooks/use-engraving-fee.ts
|
|
144
|
+
var import_react_query2 = require("@tanstack/react-query");
|
|
145
|
+
function useEngravingFee(templateId, currency) {
|
|
146
|
+
return (0, import_react_query2.useQuery)({
|
|
147
|
+
queryKey: ["engraving-fee", templateId, currency],
|
|
148
|
+
queryFn: () => fetchEngravingFee(templateId, currency),
|
|
149
|
+
enabled: !!templateId && !!currency,
|
|
150
|
+
staleTime: 1e3 * 60
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/lib/utils.ts
|
|
155
|
+
function hasValue(v) {
|
|
156
|
+
const s = String(v == null ? "" : v).trim();
|
|
157
|
+
return s.length > 0 && s !== "false";
|
|
158
|
+
}
|
|
159
|
+
function isElementVisible(el, values) {
|
|
160
|
+
const rules = el.conditions && el.conditions.rules;
|
|
161
|
+
if (!rules || rules.length === 0) return true;
|
|
162
|
+
const logic = el.conditions && el.conditions.logic || "all";
|
|
163
|
+
const checks = rules.map((r) => {
|
|
164
|
+
const actual = values[r.elementId] || "";
|
|
165
|
+
const operator = r.operator || "equals";
|
|
166
|
+
const expected = r.value != null ? r.value : r.equals != null ? r.equals : "";
|
|
167
|
+
if (operator === "exists") return hasValue(actual);
|
|
168
|
+
if (operator === "not_exists") return !hasValue(actual);
|
|
169
|
+
if (operator === "not_equals") return actual !== expected;
|
|
170
|
+
return actual === expected;
|
|
171
|
+
});
|
|
172
|
+
return logic === "any" ? checks.some(Boolean) : checks.every(Boolean);
|
|
173
|
+
}
|
|
174
|
+
function formatMoney(amountCents, currency) {
|
|
175
|
+
try {
|
|
176
|
+
return new Intl.NumberFormat(void 0, {
|
|
177
|
+
style: "currency",
|
|
178
|
+
currency: (currency || "usd").toUpperCase()
|
|
179
|
+
}).format((amountCents || 0) / 100);
|
|
180
|
+
} catch {
|
|
181
|
+
return ((amountCents || 0) / 100).toFixed(2);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function variantPrice(v) {
|
|
185
|
+
return v && v.calculated_price ? v.calculated_price.calculated_amount : void 0;
|
|
186
|
+
}
|
|
187
|
+
function variantCurrency(v) {
|
|
188
|
+
return v && v.calculated_price && v.calculated_price.currency_code || "usd";
|
|
189
|
+
}
|
|
190
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
191
|
+
0 && (module.exports = {
|
|
192
|
+
addEngravingLine,
|
|
193
|
+
fetchEngravingConfig,
|
|
194
|
+
fetchEngravingFee,
|
|
195
|
+
fetchEngravingProduct,
|
|
196
|
+
fetchRegionId,
|
|
197
|
+
formatMoney,
|
|
198
|
+
isElementVisible,
|
|
199
|
+
storeHeaders,
|
|
200
|
+
useEngraving,
|
|
201
|
+
useEngravingFee,
|
|
202
|
+
variantCurrency,
|
|
203
|
+
variantPrice
|
|
204
|
+
});
|
|
205
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/hooks/use-engraving.ts","../src/lib/fetch.ts","../src/hooks/use-engraving-fee.ts","../src/lib/utils.ts"],"sourcesContent":["// Storefront hooks\nexport { useEngraving } from './hooks/use-engraving'\nexport { useEngravingFee } from './hooks/use-engraving-fee'\n\n// Data helpers\nexport {\n fetchEngravingConfig,\n fetchRegionId,\n fetchEngravingProduct,\n fetchEngravingFee,\n addEngravingLine,\n storeHeaders,\n} from './lib/fetch'\n\n// Pure helpers\nexport { isElementVisible, formatMoney, variantPrice, variantCurrency } from './lib/utils'\n\n// Types\nexport type {\n EngravingElementType,\n EngravingOption,\n EngravingConditionOperator,\n EngravingConditionRule,\n EngravingConditions,\n EngravingPreviewPlacement,\n EngravingElement,\n EngravingTemplate,\n EngravingConfig,\n EngravingVariant,\n EngravingProduct,\n EngravingFieldValues,\n AddEngravingInput,\n AddEngravingResult,\n ResolvedEngraving,\n} from './types'\n","'use client'\n\nimport { useQuery } from '@tanstack/react-query'\nimport { fetchEngravingConfig, fetchRegionId, fetchEngravingProduct } from '../lib/fetch'\nimport type { ResolvedEngraving } from '../types'\n\n/**\n * Resolves whether a product can be engraved: engraving must be enabled on the\n * store AND the product must carry `metadata.engraving_template_id` pointing at\n * an active template. Returns null when engraving shouldn't show for this\n * product, so the storefront button can simply render nothing.\n *\n * @example\n * const { data } = useEngraving(product.id)\n * if (!data) return null\n * // data.template, data.product\n */\nexport function useEngraving(productId: string) {\n return useQuery<ResolvedEngraving | null>({\n queryKey: ['engraving-pdp', productId],\n queryFn: async () => {\n const config = await fetchEngravingConfig()\n if (!config || !config.enabled) return null\n const regionId = await fetchRegionId()\n if (!regionId) return null\n const product = await fetchEngravingProduct(productId, regionId)\n if (!product) return null\n const templateId =\n product.metadata && (product.metadata.engraving_template_id as string | undefined)\n if (!templateId) return null\n const template = (config.templates || []).find(\n (t) => t.id === templateId && t.status === 'active',\n )\n if (!template) return null\n return { template, product }\n },\n staleTime: 1000 * 60, // 1 minute\n enabled: !!productId,\n })\n}\n","'use client'\n\nimport type {\n AddEngravingInput,\n AddEngravingResult,\n EngravingConfig,\n EngravingProduct,\n} from '../types'\n\nfunction resolveEnv(key: string): string | undefined {\n if (key === 'NEXT_PUBLIC_MEDUSA_BACKEND_URL') return process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL\n if (key === 'NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY') return process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY\n if (key === 'NEXT_PUBLIC_STORE_ID') return process.env.NEXT_PUBLIC_STORE_ID\n return undefined\n}\n\nfunction baseUrl(): string {\n return resolveEnv('NEXT_PUBLIC_MEDUSA_BACKEND_URL') ?? 'http://localhost:9000'\n}\n\n/** Public store headers — publishable key + (optional) multi-tenant env id. */\nexport function storeHeaders(extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = { ...(extra ?? {}) }\n const key = resolveEnv('NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY')\n const storeId = resolveEnv('NEXT_PUBLIC_STORE_ID')\n if (key) headers['x-publishable-api-key'] = key\n if (storeId) headers['x-store-environment-id'] = storeId\n return headers\n}\n\n/** Reads store.metadata.plugins.engraving via the public integrations endpoint. */\nexport async function fetchEngravingConfig(): Promise<EngravingConfig | null> {\n try {\n const res = await fetch(`${baseUrl()}/store/integrations/active`, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as Record<string, unknown>\n return (data && (data.engraving as EngravingConfig)) || null\n } catch {\n return null\n }\n}\n\n/** First region id — used for pricing context when no cart region is known yet. */\nexport async function fetchRegionId(): Promise<string | null> {\n try {\n const res = await fetch(`${baseUrl()}/store/regions`, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as { regions?: Array<{ id: string }> }\n return (data.regions && data.regions[0] && data.regions[0].id) || null\n } catch {\n return null\n }\n}\n\n/** Product with metadata, images and per-variant calculated price in a region. */\nexport async function fetchEngravingProduct(\n productId: string,\n regionId: string,\n): Promise<EngravingProduct | null> {\n try {\n const fields = 'id,title,thumbnail,metadata,*images,*variants,*variants.calculated_price'\n const url =\n `${baseUrl()}/store/products/${productId}` +\n `?region_id=${encodeURIComponent(regionId)}&fields=${encodeURIComponent(fields)}`\n const res = await fetch(url, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as { product?: EngravingProduct }\n return data.product || null\n } catch {\n return null\n }\n}\n\n/**\n * Live per-currency fee, resolved server-side from the store's locked FX rate.\n * Covers every currency the store supports — not just the ones in the template's\n * stored fee map (which can go stale when a currency is added later). Returns\n * null when the currency is genuinely unsupported.\n */\nexport async function fetchEngravingFee(\n templateId: string,\n currency: string,\n): Promise<number | null> {\n try {\n const url =\n `${baseUrl()}/store/engraving/fee` +\n `?template_id=${encodeURIComponent(templateId)}¤cy=${encodeURIComponent(currency)}`\n const res = await fetch(url, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as { fee?: number | null }\n return typeof data.fee === 'number' ? data.fee : null\n } catch {\n return null\n }\n}\n\n/**\n * Add an engraved line to a cart. The server reprices the line to base + the\n * per-currency engraving fee and snapshots the selection on the line metadata.\n */\nexport async function addEngravingLine(\n cartId: string,\n input: AddEngravingInput,\n): Promise<AddEngravingResult> {\n try {\n const res = await fetch(`${baseUrl()}/store/carts/${cartId}/line-items-engraving`, {\n method: 'POST',\n headers: storeHeaders({ 'Content-Type': 'application/json' }),\n body: JSON.stringify(input),\n })\n if (res.ok) return { ok: true }\n const data = (await res.json().catch(() => ({}))) as { message?: string; error?: string; errors?: string[] }\n const error =\n (data.errors && data.errors.join('; ')) ||\n data.error ||\n data.message ||\n `Could not add engraving (${res.status})`\n return { ok: false, error }\n } catch (e) {\n return { ok: false, error: e instanceof Error ? e.message : 'Network error' }\n }\n}\n","'use client'\n\nimport { useQuery } from '@tanstack/react-query'\nimport { fetchEngravingFee } from '../lib/fetch'\n\n/**\n * Live engraving fee for a template in a given currency, resolved server-side\n * from the store's locked FX rate (so it covers every supported currency and\n * matches exactly what the add-to-cart route charges). Returns `undefined`\n * while loading and `null` when the currency is unsupported.\n *\n * @example\n * const { data: fee, isLoading } = useEngravingFee(template.id, cart.currency_code)\n */\nexport function useEngravingFee(templateId: string, currency: string) {\n return useQuery<number | null>({\n queryKey: ['engraving-fee', templateId, currency],\n queryFn: () => fetchEngravingFee(templateId, currency),\n enabled: !!templateId && !!currency,\n staleTime: 1000 * 60,\n })\n}\n","import type { EngravingElement, EngravingFieldValues, EngravingVariant } from '../types'\n\nfunction hasValue(v: string | undefined): boolean {\n const s = String(v == null ? '' : v).trim()\n return s.length > 0 && s !== 'false'\n}\n\n/**\n * Conditional show/hide for an engraving field — mirrors the admin builder and\n * the Medusa server-side validation so the storefront, preview and server agree.\n */\nexport function isElementVisible(\n el: EngravingElement,\n values: EngravingFieldValues,\n): boolean {\n const rules = el.conditions && el.conditions.rules\n if (!rules || rules.length === 0) return true\n const logic = (el.conditions && el.conditions.logic) || 'all'\n const checks = rules.map((r) => {\n const actual = values[r.elementId] || ''\n const operator = r.operator || 'equals'\n const expected = r.value != null ? r.value : r.equals != null ? r.equals : ''\n if (operator === 'exists') return hasValue(actual)\n if (operator === 'not_exists') return !hasValue(actual)\n if (operator === 'not_equals') return actual !== expected\n return actual === expected\n })\n return logic === 'any' ? checks.some(Boolean) : checks.every(Boolean)\n}\n\n/** Format a minor-unit amount as currency (e.g. 1000, 'sgd' → \"SGD 10.00\"). */\nexport function formatMoney(amountCents: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency: (currency || 'usd').toUpperCase(),\n }).format((amountCents || 0) / 100)\n } catch {\n return ((amountCents || 0) / 100).toFixed(2)\n }\n}\n\nexport function variantPrice(v?: EngravingVariant): number | undefined {\n return v && v.calculated_price ? v.calculated_price.calculated_amount : undefined\n}\n\nexport function variantCurrency(v?: EngravingVariant): string {\n return (v && v.calculated_price && v.calculated_price.currency_code) || 'usd'\n}\n"],"mappings":"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","names":["import_react_query"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// src/hooks/use-engraving.ts
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
|
|
4
|
+
// src/lib/fetch.ts
|
|
5
|
+
function resolveEnv(key) {
|
|
6
|
+
if (key === "NEXT_PUBLIC_MEDUSA_BACKEND_URL") return process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL;
|
|
7
|
+
if (key === "NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY") return process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY;
|
|
8
|
+
if (key === "NEXT_PUBLIC_STORE_ID") return process.env.NEXT_PUBLIC_STORE_ID;
|
|
9
|
+
return void 0;
|
|
10
|
+
}
|
|
11
|
+
function baseUrl() {
|
|
12
|
+
return resolveEnv("NEXT_PUBLIC_MEDUSA_BACKEND_URL") ?? "http://localhost:9000";
|
|
13
|
+
}
|
|
14
|
+
function storeHeaders(extra) {
|
|
15
|
+
const headers = { ...extra ?? {} };
|
|
16
|
+
const key = resolveEnv("NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY");
|
|
17
|
+
const storeId = resolveEnv("NEXT_PUBLIC_STORE_ID");
|
|
18
|
+
if (key) headers["x-publishable-api-key"] = key;
|
|
19
|
+
if (storeId) headers["x-store-environment-id"] = storeId;
|
|
20
|
+
return headers;
|
|
21
|
+
}
|
|
22
|
+
async function fetchEngravingConfig() {
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(`${baseUrl()}/store/integrations/active`, { headers: storeHeaders() });
|
|
25
|
+
if (!res.ok) return null;
|
|
26
|
+
const data = await res.json();
|
|
27
|
+
return data && data.engraving || null;
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function fetchRegionId() {
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(`${baseUrl()}/store/regions`, { headers: storeHeaders() });
|
|
35
|
+
if (!res.ok) return null;
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
return data.regions && data.regions[0] && data.regions[0].id || null;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function fetchEngravingProduct(productId, regionId) {
|
|
43
|
+
try {
|
|
44
|
+
const fields = "id,title,thumbnail,metadata,*images,*variants,*variants.calculated_price";
|
|
45
|
+
const url = `${baseUrl()}/store/products/${productId}?region_id=${encodeURIComponent(regionId)}&fields=${encodeURIComponent(fields)}`;
|
|
46
|
+
const res = await fetch(url, { headers: storeHeaders() });
|
|
47
|
+
if (!res.ok) return null;
|
|
48
|
+
const data = await res.json();
|
|
49
|
+
return data.product || null;
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function fetchEngravingFee(templateId, currency) {
|
|
55
|
+
try {
|
|
56
|
+
const url = `${baseUrl()}/store/engraving/fee?template_id=${encodeURIComponent(templateId)}¤cy=${encodeURIComponent(currency)}`;
|
|
57
|
+
const res = await fetch(url, { headers: storeHeaders() });
|
|
58
|
+
if (!res.ok) return null;
|
|
59
|
+
const data = await res.json();
|
|
60
|
+
return typeof data.fee === "number" ? data.fee : null;
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function addEngravingLine(cartId, input) {
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch(`${baseUrl()}/store/carts/${cartId}/line-items-engraving`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: storeHeaders({ "Content-Type": "application/json" }),
|
|
70
|
+
body: JSON.stringify(input)
|
|
71
|
+
});
|
|
72
|
+
if (res.ok) return { ok: true };
|
|
73
|
+
const data = await res.json().catch(() => ({}));
|
|
74
|
+
const error = data.errors && data.errors.join("; ") || data.error || data.message || `Could not add engraving (${res.status})`;
|
|
75
|
+
return { ok: false, error };
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return { ok: false, error: e instanceof Error ? e.message : "Network error" };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/hooks/use-engraving.ts
|
|
82
|
+
function useEngraving(productId) {
|
|
83
|
+
return useQuery({
|
|
84
|
+
queryKey: ["engraving-pdp", productId],
|
|
85
|
+
queryFn: async () => {
|
|
86
|
+
const config = await fetchEngravingConfig();
|
|
87
|
+
if (!config || !config.enabled) return null;
|
|
88
|
+
const regionId = await fetchRegionId();
|
|
89
|
+
if (!regionId) return null;
|
|
90
|
+
const product = await fetchEngravingProduct(productId, regionId);
|
|
91
|
+
if (!product) return null;
|
|
92
|
+
const templateId = product.metadata && product.metadata.engraving_template_id;
|
|
93
|
+
if (!templateId) return null;
|
|
94
|
+
const template = (config.templates || []).find(
|
|
95
|
+
(t) => t.id === templateId && t.status === "active"
|
|
96
|
+
);
|
|
97
|
+
if (!template) return null;
|
|
98
|
+
return { template, product };
|
|
99
|
+
},
|
|
100
|
+
staleTime: 1e3 * 60,
|
|
101
|
+
// 1 minute
|
|
102
|
+
enabled: !!productId
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/hooks/use-engraving-fee.ts
|
|
107
|
+
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
108
|
+
function useEngravingFee(templateId, currency) {
|
|
109
|
+
return useQuery2({
|
|
110
|
+
queryKey: ["engraving-fee", templateId, currency],
|
|
111
|
+
queryFn: () => fetchEngravingFee(templateId, currency),
|
|
112
|
+
enabled: !!templateId && !!currency,
|
|
113
|
+
staleTime: 1e3 * 60
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/lib/utils.ts
|
|
118
|
+
function hasValue(v) {
|
|
119
|
+
const s = String(v == null ? "" : v).trim();
|
|
120
|
+
return s.length > 0 && s !== "false";
|
|
121
|
+
}
|
|
122
|
+
function isElementVisible(el, values) {
|
|
123
|
+
const rules = el.conditions && el.conditions.rules;
|
|
124
|
+
if (!rules || rules.length === 0) return true;
|
|
125
|
+
const logic = el.conditions && el.conditions.logic || "all";
|
|
126
|
+
const checks = rules.map((r) => {
|
|
127
|
+
const actual = values[r.elementId] || "";
|
|
128
|
+
const operator = r.operator || "equals";
|
|
129
|
+
const expected = r.value != null ? r.value : r.equals != null ? r.equals : "";
|
|
130
|
+
if (operator === "exists") return hasValue(actual);
|
|
131
|
+
if (operator === "not_exists") return !hasValue(actual);
|
|
132
|
+
if (operator === "not_equals") return actual !== expected;
|
|
133
|
+
return actual === expected;
|
|
134
|
+
});
|
|
135
|
+
return logic === "any" ? checks.some(Boolean) : checks.every(Boolean);
|
|
136
|
+
}
|
|
137
|
+
function formatMoney(amountCents, currency) {
|
|
138
|
+
try {
|
|
139
|
+
return new Intl.NumberFormat(void 0, {
|
|
140
|
+
style: "currency",
|
|
141
|
+
currency: (currency || "usd").toUpperCase()
|
|
142
|
+
}).format((amountCents || 0) / 100);
|
|
143
|
+
} catch {
|
|
144
|
+
return ((amountCents || 0) / 100).toFixed(2);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function variantPrice(v) {
|
|
148
|
+
return v && v.calculated_price ? v.calculated_price.calculated_amount : void 0;
|
|
149
|
+
}
|
|
150
|
+
function variantCurrency(v) {
|
|
151
|
+
return v && v.calculated_price && v.calculated_price.currency_code || "usd";
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
addEngravingLine,
|
|
155
|
+
fetchEngravingConfig,
|
|
156
|
+
fetchEngravingFee,
|
|
157
|
+
fetchEngravingProduct,
|
|
158
|
+
fetchRegionId,
|
|
159
|
+
formatMoney,
|
|
160
|
+
isElementVisible,
|
|
161
|
+
storeHeaders,
|
|
162
|
+
useEngraving,
|
|
163
|
+
useEngravingFee,
|
|
164
|
+
variantCurrency,
|
|
165
|
+
variantPrice
|
|
166
|
+
};
|
|
167
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-engraving.ts","../src/lib/fetch.ts","../src/hooks/use-engraving-fee.ts","../src/lib/utils.ts"],"sourcesContent":["'use client'\n\nimport { useQuery } from '@tanstack/react-query'\nimport { fetchEngravingConfig, fetchRegionId, fetchEngravingProduct } from '../lib/fetch'\nimport type { ResolvedEngraving } from '../types'\n\n/**\n * Resolves whether a product can be engraved: engraving must be enabled on the\n * store AND the product must carry `metadata.engraving_template_id` pointing at\n * an active template. Returns null when engraving shouldn't show for this\n * product, so the storefront button can simply render nothing.\n *\n * @example\n * const { data } = useEngraving(product.id)\n * if (!data) return null\n * // data.template, data.product\n */\nexport function useEngraving(productId: string) {\n return useQuery<ResolvedEngraving | null>({\n queryKey: ['engraving-pdp', productId],\n queryFn: async () => {\n const config = await fetchEngravingConfig()\n if (!config || !config.enabled) return null\n const regionId = await fetchRegionId()\n if (!regionId) return null\n const product = await fetchEngravingProduct(productId, regionId)\n if (!product) return null\n const templateId =\n product.metadata && (product.metadata.engraving_template_id as string | undefined)\n if (!templateId) return null\n const template = (config.templates || []).find(\n (t) => t.id === templateId && t.status === 'active',\n )\n if (!template) return null\n return { template, product }\n },\n staleTime: 1000 * 60, // 1 minute\n enabled: !!productId,\n })\n}\n","'use client'\n\nimport type {\n AddEngravingInput,\n AddEngravingResult,\n EngravingConfig,\n EngravingProduct,\n} from '../types'\n\nfunction resolveEnv(key: string): string | undefined {\n if (key === 'NEXT_PUBLIC_MEDUSA_BACKEND_URL') return process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL\n if (key === 'NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY') return process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY\n if (key === 'NEXT_PUBLIC_STORE_ID') return process.env.NEXT_PUBLIC_STORE_ID\n return undefined\n}\n\nfunction baseUrl(): string {\n return resolveEnv('NEXT_PUBLIC_MEDUSA_BACKEND_URL') ?? 'http://localhost:9000'\n}\n\n/** Public store headers — publishable key + (optional) multi-tenant env id. */\nexport function storeHeaders(extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = { ...(extra ?? {}) }\n const key = resolveEnv('NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY')\n const storeId = resolveEnv('NEXT_PUBLIC_STORE_ID')\n if (key) headers['x-publishable-api-key'] = key\n if (storeId) headers['x-store-environment-id'] = storeId\n return headers\n}\n\n/** Reads store.metadata.plugins.engraving via the public integrations endpoint. */\nexport async function fetchEngravingConfig(): Promise<EngravingConfig | null> {\n try {\n const res = await fetch(`${baseUrl()}/store/integrations/active`, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as Record<string, unknown>\n return (data && (data.engraving as EngravingConfig)) || null\n } catch {\n return null\n }\n}\n\n/** First region id — used for pricing context when no cart region is known yet. */\nexport async function fetchRegionId(): Promise<string | null> {\n try {\n const res = await fetch(`${baseUrl()}/store/regions`, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as { regions?: Array<{ id: string }> }\n return (data.regions && data.regions[0] && data.regions[0].id) || null\n } catch {\n return null\n }\n}\n\n/** Product with metadata, images and per-variant calculated price in a region. */\nexport async function fetchEngravingProduct(\n productId: string,\n regionId: string,\n): Promise<EngravingProduct | null> {\n try {\n const fields = 'id,title,thumbnail,metadata,*images,*variants,*variants.calculated_price'\n const url =\n `${baseUrl()}/store/products/${productId}` +\n `?region_id=${encodeURIComponent(regionId)}&fields=${encodeURIComponent(fields)}`\n const res = await fetch(url, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as { product?: EngravingProduct }\n return data.product || null\n } catch {\n return null\n }\n}\n\n/**\n * Live per-currency fee, resolved server-side from the store's locked FX rate.\n * Covers every currency the store supports — not just the ones in the template's\n * stored fee map (which can go stale when a currency is added later). Returns\n * null when the currency is genuinely unsupported.\n */\nexport async function fetchEngravingFee(\n templateId: string,\n currency: string,\n): Promise<number | null> {\n try {\n const url =\n `${baseUrl()}/store/engraving/fee` +\n `?template_id=${encodeURIComponent(templateId)}¤cy=${encodeURIComponent(currency)}`\n const res = await fetch(url, { headers: storeHeaders() })\n if (!res.ok) return null\n const data = (await res.json()) as { fee?: number | null }\n return typeof data.fee === 'number' ? data.fee : null\n } catch {\n return null\n }\n}\n\n/**\n * Add an engraved line to a cart. The server reprices the line to base + the\n * per-currency engraving fee and snapshots the selection on the line metadata.\n */\nexport async function addEngravingLine(\n cartId: string,\n input: AddEngravingInput,\n): Promise<AddEngravingResult> {\n try {\n const res = await fetch(`${baseUrl()}/store/carts/${cartId}/line-items-engraving`, {\n method: 'POST',\n headers: storeHeaders({ 'Content-Type': 'application/json' }),\n body: JSON.stringify(input),\n })\n if (res.ok) return { ok: true }\n const data = (await res.json().catch(() => ({}))) as { message?: string; error?: string; errors?: string[] }\n const error =\n (data.errors && data.errors.join('; ')) ||\n data.error ||\n data.message ||\n `Could not add engraving (${res.status})`\n return { ok: false, error }\n } catch (e) {\n return { ok: false, error: e instanceof Error ? e.message : 'Network error' }\n }\n}\n","'use client'\n\nimport { useQuery } from '@tanstack/react-query'\nimport { fetchEngravingFee } from '../lib/fetch'\n\n/**\n * Live engraving fee for a template in a given currency, resolved server-side\n * from the store's locked FX rate (so it covers every supported currency and\n * matches exactly what the add-to-cart route charges). Returns `undefined`\n * while loading and `null` when the currency is unsupported.\n *\n * @example\n * const { data: fee, isLoading } = useEngravingFee(template.id, cart.currency_code)\n */\nexport function useEngravingFee(templateId: string, currency: string) {\n return useQuery<number | null>({\n queryKey: ['engraving-fee', templateId, currency],\n queryFn: () => fetchEngravingFee(templateId, currency),\n enabled: !!templateId && !!currency,\n staleTime: 1000 * 60,\n })\n}\n","import type { EngravingElement, EngravingFieldValues, EngravingVariant } from '../types'\n\nfunction hasValue(v: string | undefined): boolean {\n const s = String(v == null ? '' : v).trim()\n return s.length > 0 && s !== 'false'\n}\n\n/**\n * Conditional show/hide for an engraving field — mirrors the admin builder and\n * the Medusa server-side validation so the storefront, preview and server agree.\n */\nexport function isElementVisible(\n el: EngravingElement,\n values: EngravingFieldValues,\n): boolean {\n const rules = el.conditions && el.conditions.rules\n if (!rules || rules.length === 0) return true\n const logic = (el.conditions && el.conditions.logic) || 'all'\n const checks = rules.map((r) => {\n const actual = values[r.elementId] || ''\n const operator = r.operator || 'equals'\n const expected = r.value != null ? r.value : r.equals != null ? r.equals : ''\n if (operator === 'exists') return hasValue(actual)\n if (operator === 'not_exists') return !hasValue(actual)\n if (operator === 'not_equals') return actual !== expected\n return actual === expected\n })\n return logic === 'any' ? checks.some(Boolean) : checks.every(Boolean)\n}\n\n/** Format a minor-unit amount as currency (e.g. 1000, 'sgd' → \"SGD 10.00\"). */\nexport function formatMoney(amountCents: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency: (currency || 'usd').toUpperCase(),\n }).format((amountCents || 0) / 100)\n } catch {\n return ((amountCents || 0) / 100).toFixed(2)\n }\n}\n\nexport function variantPrice(v?: EngravingVariant): number | undefined {\n return v && v.calculated_price ? v.calculated_price.calculated_amount : undefined\n}\n\nexport function variantCurrency(v?: EngravingVariant): string {\n return (v && v.calculated_price && v.calculated_price.currency_code) || 'usd'\n}\n"],"mappings":"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","names":["useQuery","useQuery"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@amboras-dev/engraving",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Engraving personalization hooks + helpers for Amboras storefronts",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": ">=18",
|
|
20
|
+
"@tanstack/react-query": ">=5"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"tsup": "^8.0.0",
|
|
24
|
+
"typescript": "^5.0.0",
|
|
25
|
+
"@tanstack/react-query": "^5.0.0",
|
|
26
|
+
"@types/react": "^18.0.0",
|
|
27
|
+
"@types/node": "^20.0.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
}
|
|
36
|
+
}
|