@hartl-services/medusa-storefront 0.2.0 → 0.3.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/README.md CHANGED
@@ -83,6 +83,19 @@ wrapper (as in the `setup` item's `lib/storefront/actions.ts`) to use them:
83
83
  |---|---|---|
84
84
  | `registerCustomerWithProfile` | 0.2.0 | `usePasswordAuth().registerWithProfile` (name, phone, default address) |
85
85
  | `getOrder` | 0.2.0 | `useAccountOrderDetail` (order lines and totals in the account) |
86
+ | `registerPartnerWithProfile` | 0.3.0 | `usePasswordAuth().registerPartner` (account, company address with optional UID, partner application) |
87
+
88
+ ## Partner views (e.g. therapists)
89
+
90
+ A partner is an approved affiliate. For server rendering,
91
+ `storefront.affiliate.isActivePartner()` answers whether the logged-in
92
+ customer is one (`loadPartnerPortalState()` gives the full state, e.g.
93
+ `pending` for a submitted application). Both are cached per request and fail
94
+ closed: logged out, partner portal switched off or an unreachable backend all
95
+ count as "not a partner". A partner registration (`registerPartner`) creates
96
+ the account with the company address as default address and submits the
97
+ application from it; while the e-mail is unconfirmed, both wait until the
98
+ first login.
86
99
 
87
100
  ## Wiring rules
88
101
 
@@ -17,6 +17,8 @@ export interface StorefrontActions {
17
17
  registerCustomer: Server["customer"]["registerCustomer"];
18
18
  /** Optional (since 0.2.0): registration with name, phone and address. */
19
19
  registerCustomerWithProfile?: Server["customer"]["registerCustomerWithProfile"];
20
+ /** Optional (since 0.3.0): partner registration with company address and partner application. */
21
+ registerPartnerWithProfile?: Server["customer"]["registerPartnerWithProfile"];
20
22
  requestLoginCode: Server["customer"]["requestLoginCode"];
21
23
  loginWithCode: Server["customer"]["loginWithCode"];
22
24
  requestCustomerPasswordReset: Server["customer"]["requestCustomerPasswordReset"];
@@ -0,0 +1,18 @@
1
+ import type { HttpTypes } from "@medusajs/types";
2
+ import type { CategoryTreeNode } from "./category-filter.js";
3
+ /** A category tree node with the metadata that carries the partner-only flag. */
4
+ export type PartnerCategoryTreeNode = CategoryTreeNode & {
5
+ category_children?: PartnerCategoryTreeNode[] | null;
6
+ metadata?: Record<string, unknown> | null;
7
+ };
8
+ /** Ids of every flagged category and all its descendants. */
9
+ export declare function collectPartnerOnlyCategoryIds(trees: PartnerCategoryTreeNode[]): Set<string>;
10
+ /** The trees without flagged categories (and their subcategories) - what a non-partner sees. */
11
+ export declare function withoutPartnerOnlyCategories<T extends PartnerCategoryTreeNode>(trees: T[]): T[];
12
+ /**
13
+ * A product only active partners may see and order: tagged
14
+ * `PARTNER_ONLY_PRODUCT_TAG` or in a partner-only category (see
15
+ * `collectPartnerOnlyCategoryIds`). The backend enforces the same rule when
16
+ * the cart is completed.
17
+ */
18
+ export declare function isPartnerOnlyProduct(product: Pick<HttpTypes.StoreProduct, "categories" | "tags">, partnerOnlyCategoryIds: ReadonlySet<string>): boolean;
@@ -0,0 +1,31 @@
1
+ import { PARTNER_ONLY_CATEGORY_METADATA_KEY, PARTNER_ONLY_PRODUCT_TAG } from "@hartl-services/medusa-contracts/paths/affiliate";
2
+ import { collectCategoryIds } from "./category-filter.js";
3
+ function isFlagged(category) {
4
+ return category.metadata?.[PARTNER_ONLY_CATEGORY_METADATA_KEY] === true;
5
+ }
6
+ /** Ids of every flagged category and all its descendants. */
7
+ export function collectPartnerOnlyCategoryIds(trees) {
8
+ const ids = new Set();
9
+ const visit = (node) => {
10
+ if (isFlagged(node)) {
11
+ collectCategoryIds(node).forEach((id) => ids.add(id));
12
+ return;
13
+ }
14
+ node.category_children?.forEach(visit);
15
+ };
16
+ trees.forEach(visit);
17
+ return ids;
18
+ }
19
+ /** The trees without flagged categories (and their subcategories) - what a non-partner sees. */
20
+ export function withoutPartnerOnlyCategories(trees) {
21
+ return trees.filter((node) => !isFlagged(node)).map((node) => (node.category_children ? { ...node, category_children: withoutPartnerOnlyCategories(node.category_children) } : node));
22
+ }
23
+ /**
24
+ * A product only active partners may see and order: tagged
25
+ * `PARTNER_ONLY_PRODUCT_TAG` or in a partner-only category (see
26
+ * `collectPartnerOnlyCategoryIds`). The backend enforces the same rule when
27
+ * the cart is completed.
28
+ */
29
+ export function isPartnerOnlyProduct(product, partnerOnlyCategoryIds) {
30
+ return (product.tags ?? []).some((tag) => tag.value === PARTNER_ONLY_PRODUCT_TAG) || (product.categories ?? []).some((category) => partnerOnlyCategoryIds.has(category.id));
31
+ }
@@ -14,8 +14,10 @@ export declare function createCustomerRegistrationSchema(t: Translate, policy: C
14
14
  export declare const registrationAddressSchema: z.ZodObject<{
15
15
  address_1: z.ZodString;
16
16
  city: z.ZodString;
17
+ company: z.ZodOptional<z.ZodString>;
17
18
  country_code: z.ZodString;
18
19
  postal_code: z.ZodString;
20
+ vat_number: z.ZodOptional<z.ZodString>;
19
21
  }, z.core.$strip>;
20
22
  /** What the server takes for a registration with profile (and optional address). */
21
23
  export declare const customerRegistrationProfileSchema: z.ZodObject<{
@@ -24,13 +26,36 @@ export declare const customerRegistrationProfileSchema: z.ZodObject<{
24
26
  address: z.ZodOptional<z.ZodObject<{
25
27
  address_1: z.ZodString;
26
28
  city: z.ZodString;
29
+ company: z.ZodOptional<z.ZodString>;
27
30
  country_code: z.ZodString;
28
31
  postal_code: z.ZodString;
32
+ vat_number: z.ZodOptional<z.ZodString>;
29
33
  }, z.core.$strip>>;
30
34
  first_name: z.ZodString;
31
35
  last_name: z.ZodString;
32
36
  phone: z.ZodString;
33
37
  }, z.core.$strip>;
38
+ /**
39
+ * A partner (e.g. therapist) registration: the profile with a complete
40
+ * company address - with a UID, or with the confirmation that the company has
41
+ * none - from which the partner application is submitted.
42
+ */
43
+ export declare const partnerRegistrationProfileSchema: z.ZodObject<{
44
+ email: z.ZodString;
45
+ password: z.ZodString;
46
+ first_name: z.ZodString;
47
+ last_name: z.ZodString;
48
+ phone: z.ZodString;
49
+ address: z.ZodObject<{
50
+ address_1: z.ZodString;
51
+ city: z.ZodString;
52
+ country_code: z.ZodString;
53
+ postal_code: z.ZodString;
54
+ vat_number: z.ZodOptional<z.ZodString>;
55
+ company: z.ZodString;
56
+ }, z.core.$strip>;
57
+ confirmed_without_vat_number: z.ZodBoolean;
58
+ }, z.core.$strip>;
34
59
  /**
35
60
  * The registration form with profile, address, a repeated password and the
36
61
  * accepted terms. Address fields are all-or-nothing: none or a complete
@@ -49,6 +74,28 @@ export declare function createCustomerRegistrationFormSchema(t: Translate, polic
49
74
  phone: z.ZodString;
50
75
  postal_code: z.ZodString;
51
76
  }, z.core.$strip>;
77
+ /**
78
+ * The partner registration form: profile and a required company address,
79
+ * an optional UID, and without UID the confirmation that the company has none.
80
+ */
81
+ export declare function createPartnerRegistrationFormSchema(t: Translate, policy: CustomerPasswordPolicy | null): z.ZodObject<{
82
+ address_1: z.ZodString;
83
+ city: z.ZodString;
84
+ company: z.ZodString;
85
+ confirmed_without_vat_number: z.ZodBoolean;
86
+ country_code: z.ZodString;
87
+ postal_code: z.ZodString;
88
+ vat_number: z.ZodString;
89
+ accept_terms: z.ZodBoolean;
90
+ confirmPassword: z.ZodString;
91
+ email: z.ZodString;
92
+ first_name: z.ZodString;
93
+ last_name: z.ZodString;
94
+ password: z.ZodString;
95
+ phone: z.ZodString;
96
+ }, z.core.$strip>;
97
+ /** The partner registration form's values as the server takes them. */
98
+ export declare function toPartnerRegistrationProfile(value: PartnerRegistrationFormValues): PartnerRegistrationProfileValues;
52
99
  /** The registration form's values as the server takes them. */
53
100
  export declare function toRegistrationProfile(value: CustomerRegistrationFormValues): CustomerRegistrationProfileValues;
54
101
  export declare function createPasswordResetSchema(t: Translate, policy: CustomerPasswordPolicy | null): z.ZodObject<{
@@ -127,25 +174,25 @@ export declare const createCheckoutAddressSchema: (t: Translate, merchantCountry
127
174
  shipping_address: z.ZodObject<{
128
175
  address_1: z.ZodString;
129
176
  city: z.ZodString;
177
+ company: z.ZodString;
130
178
  country_code: z.ZodString;
131
179
  postal_code: z.ZodString;
132
180
  first_name: z.ZodString;
133
181
  last_name: z.ZodString;
134
182
  phone: z.ZodString;
135
183
  address_2: z.ZodString;
136
- company: z.ZodString;
137
184
  province: z.ZodString;
138
185
  }, z.core.$strip>;
139
186
  billing_address: z.ZodObject<{
140
187
  address_1: z.ZodString;
141
188
  city: z.ZodString;
189
+ company: z.ZodString;
142
190
  country_code: z.ZodString;
143
191
  postal_code: z.ZodString;
144
192
  first_name: z.ZodString;
145
193
  last_name: z.ZodString;
146
194
  phone: z.ZodString;
147
195
  address_2: z.ZodString;
148
- company: z.ZodString;
149
196
  province: z.ZodString;
150
197
  }, z.core.$strip>;
151
198
  vat_number: z.ZodString;
@@ -153,6 +200,8 @@ export declare const createCheckoutAddressSchema: (t: Translate, merchantCountry
153
200
  export type CustomerAuthValues = z.infer<typeof customerAuthSchema>;
154
201
  export type CustomerRegistrationProfileValues = z.infer<typeof customerRegistrationProfileSchema>;
155
202
  export type CustomerRegistrationFormValues = z.infer<ReturnType<typeof createCustomerRegistrationFormSchema>>;
203
+ export type PartnerRegistrationProfileValues = z.infer<typeof partnerRegistrationProfileSchema>;
204
+ export type PartnerRegistrationFormValues = z.infer<ReturnType<typeof createPartnerRegistrationFormSchema>>;
156
205
  export type LoginCodeRequestValues = z.infer<ReturnType<typeof createLoginCodeRequestSchema>>;
157
206
  export type PasswordResetValues = z.infer<ReturnType<typeof createPasswordResetSchema>>;
158
207
  export type VerificationResendValues = z.infer<ReturnType<typeof createVerificationResendSchema>>;
@@ -31,8 +31,11 @@ export function createCustomerRegistrationSchema(t, policy) {
31
31
  export const registrationAddressSchema = z.object({
32
32
  address_1: z.string().trim().min(1),
33
33
  city: z.string().trim().min(1),
34
+ company: z.string().trim().optional(),
34
35
  country_code: z.string().trim().min(1),
35
36
  postal_code: z.string().trim().min(1),
37
+ /** Stored in the address metadata, where the UID check reads it. */
38
+ vat_number: z.string().trim().optional(),
36
39
  });
37
40
  /** What the server takes for a registration with profile (and optional address). */
38
41
  export const customerRegistrationProfileSchema = customerAuthSchema.extend({
@@ -42,13 +45,18 @@ export const customerRegistrationProfileSchema = customerAuthSchema.extend({
42
45
  phone: z.string().trim(),
43
46
  });
44
47
  /**
45
- * The registration form with profile, address, a repeated password and the
46
- * accepted terms. Address fields are all-or-nothing: none or a complete
47
- * address.
48
+ * A partner (e.g. therapist) registration: the profile with a complete
49
+ * company address - with a UID, or with the confirmation that the company has
50
+ * none - from which the partner application is submitted.
48
51
  */
49
- export function createCustomerRegistrationFormSchema(t, policy) {
50
- return z
51
- .object({
52
+ export const partnerRegistrationProfileSchema = customerRegistrationProfileSchema
53
+ .extend({
54
+ address: registrationAddressSchema.extend({ company: z.string().trim().min(1) }),
55
+ confirmed_without_vat_number: z.boolean(),
56
+ })
57
+ .refine((value) => Boolean(value.address.vat_number) || value.confirmed_without_vat_number, { path: ["confirmed_without_vat_number"] });
58
+ function registrationFormFields(t, policy) {
59
+ return {
52
60
  accept_terms: z.boolean().refine((accepted) => accepted, t("registration.terms_required")),
53
61
  address_1: z.string().trim(),
54
62
  city: z.string().trim(),
@@ -60,7 +68,16 @@ export function createCustomerRegistrationFormSchema(t, policy) {
60
68
  password: createNewPasswordSchema(t, policy),
61
69
  phone: z.string().trim(),
62
70
  postal_code: z.string().trim(),
63
- })
71
+ };
72
+ }
73
+ /**
74
+ * The registration form with profile, address, a repeated password and the
75
+ * accepted terms. Address fields are all-or-nothing: none or a complete
76
+ * address.
77
+ */
78
+ export function createCustomerRegistrationFormSchema(t, policy) {
79
+ return z
80
+ .object(registrationFormFields(t, policy))
64
81
  .superRefine((value, context) => {
65
82
  if (value.password !== value.confirmPassword) {
66
83
  context.addIssue({ code: "custom", message: t("form.passwords_mismatch"), path: ["confirmPassword"] });
@@ -80,6 +97,55 @@ export function createCustomerRegistrationFormSchema(t, policy) {
80
97
  }
81
98
  });
82
99
  }
100
+ /**
101
+ * The partner registration form: profile and a required company address,
102
+ * an optional UID, and without UID the confirmation that the company has none.
103
+ */
104
+ export function createPartnerRegistrationFormSchema(t, policy) {
105
+ return z
106
+ .object({
107
+ ...registrationFormFields(t, policy),
108
+ address_1: z.string().trim().min(1, t("address.address_1_required")),
109
+ city: z.string().trim().min(1, t("address.city_required")),
110
+ company: z.string().trim().min(1, t("company_address.company_required")),
111
+ confirmed_without_vat_number: z.boolean(),
112
+ country_code: z.string().trim().min(1, t("address.country_required")),
113
+ postal_code: z.string().trim().min(1, t("address.postal_code_required")),
114
+ vat_number: z.string().refine((value) => {
115
+ const vatNumber = value.replace(/\s+/g, "");
116
+ return !vatNumber || (vatNumber.length >= 4 && vatNumber.length <= 32);
117
+ }, t("company_address.vat_number_invalid")),
118
+ })
119
+ .superRefine((value, context) => {
120
+ if (value.password !== value.confirmPassword) {
121
+ context.addIssue({ code: "custom", message: t("form.passwords_mismatch"), path: ["confirmPassword"] });
122
+ }
123
+ if (!value.vat_number.trim() && !value.confirmed_without_vat_number) {
124
+ context.addIssue({ code: "custom", message: t("affiliate_application.confirm_without_vat_number"), path: ["confirmed_without_vat_number"] });
125
+ }
126
+ });
127
+ }
128
+ /** The partner registration form's values as the server takes them. */
129
+ export function toPartnerRegistrationProfile(value) {
130
+ const vatNumber = value.vat_number.replace(/\s+/g, "").toUpperCase();
131
+ return {
132
+ address: {
133
+ address_1: value.address_1.trim(),
134
+ city: value.city.trim(),
135
+ company: value.company.trim(),
136
+ country_code: value.country_code.trim().toLowerCase(),
137
+ postal_code: value.postal_code.trim(),
138
+ ...(vatNumber ? { vat_number: vatNumber } : {}),
139
+ },
140
+ // Only meaningful without a UID; the backend ignores it otherwise.
141
+ confirmed_without_vat_number: !vatNumber && value.confirmed_without_vat_number,
142
+ email: value.email.trim(),
143
+ first_name: value.first_name.trim(),
144
+ last_name: value.last_name.trim(),
145
+ password: value.password,
146
+ phone: value.phone.trim(),
147
+ };
148
+ }
83
149
  /** The registration form's values as the server takes them. */
84
150
  export function toRegistrationProfile(value) {
85
151
  const hasAddress = Boolean(value.address_1 && value.postal_code && value.city && value.country_code);
@@ -18,6 +18,7 @@ export * from "./cart/coupon-promotions.js";
18
18
  export * from "./cart/payment-session.js";
19
19
  export * from "./cart/refunded-cart.js";
20
20
  export * from "./catalog/category-filter.js";
21
+ export * from "./catalog/partner-only.js";
21
22
  export * from "./catalog/inventory.js";
22
23
  export * from "./catalog/medusa-product-image.js";
23
24
  export * from "./catalog/product-price.js";
@@ -19,6 +19,7 @@ export * from "./cart/coupon-promotions.js";
19
19
  export * from "./cart/payment-session.js";
20
20
  export * from "./cart/refunded-cart.js";
21
21
  export * from "./catalog/category-filter.js";
22
+ export * from "./catalog/partner-only.js";
22
23
  export * from "./catalog/inventory.js";
23
24
  export * from "./catalog/medusa-product-image.js";
24
25
  export * from "./catalog/product-price.js";
@@ -1,5 +1,5 @@
1
1
  /** Where an error happened; the shop's error tracker files it under this area. */
2
- export type StorefrontErrorArea = "checkout" | "customer-auth" | "plugin-features" | "tax-compliance";
2
+ export type StorefrontErrorArea = "affiliate" | "checkout" | "customer-auth" | "plugin-features" | "tax-compliance";
3
3
  export interface StorefrontErrorReport {
4
4
  area: StorefrontErrorArea;
5
5
  /** Extra data for tracing (cart id, status, ...); never addresses or payment details. */
@@ -8,6 +8,8 @@ export declare const textsDe: {
8
8
  readonly "form.passwords_mismatch": "Die Passwörter stimmen nicht überein.";
9
9
  readonly "registration.terms_required": "Bitte akzeptiere die Nutzungsbedingungen und Datenschutzrichtlinien.";
10
10
  readonly "registration.address_not_saved": "Dein Konto wurde angelegt, die Adresse konnte aber nicht gespeichert werden. Du kannst sie in deinem Konto nachtragen.";
11
+ readonly "partner_registration.unavailable": "Die Registrierung als Partner ist derzeit nicht möglich.";
12
+ readonly "partner_registration.application_not_submitted": "Dein Konto wurde angelegt, die Bewerbung konnte aber nicht übermittelt werden. Bitte melde dich bei uns.";
11
13
  readonly "form.email_required": "Bitte gib deine E-Mail-Adresse ein.";
12
14
  readonly "form.email_invalid": "Bitte gib eine gültige E-Mail-Adresse ein.";
13
15
  readonly "form.login_code_invalid": "Bitte gib den {length}-stelligen Code ein.";
@@ -10,6 +10,8 @@ export const textsDe = {
10
10
  "form.passwords_mismatch": "Die Passwörter stimmen nicht überein.",
11
11
  "registration.terms_required": "Bitte akzeptiere die Nutzungsbedingungen und Datenschutzrichtlinien.",
12
12
  "registration.address_not_saved": "Dein Konto wurde angelegt, die Adresse konnte aber nicht gespeichert werden. Du kannst sie in deinem Konto nachtragen.",
13
+ "partner_registration.unavailable": "Die Registrierung als Partner ist derzeit nicht möglich.",
14
+ "partner_registration.application_not_submitted": "Dein Konto wurde angelegt, die Bewerbung konnte aber nicht übermittelt werden. Bitte melde dich bei uns.",
13
15
  "form.email_required": "Bitte gib deine E-Mail-Adresse ein.",
14
16
  "form.email_invalid": "Bitte gib eine gültige E-Mail-Adresse ein.",
15
17
  "form.login_code_invalid": "Bitte gib den {length}-stelligen Code ein.",
@@ -1,5 +1,5 @@
1
1
  import type { StorefrontBrowser } from "../browser/index.js";
2
- import type { CustomerAuthValues, CustomerRegistrationProfileValues, PasswordResetValues, VerificationResendValues } from "../core/form-values.js";
2
+ import type { CustomerAuthValues, CustomerRegistrationProfileValues, PartnerRegistrationProfileValues, PasswordResetValues, VerificationResendValues } from "../core/form-values.js";
3
3
  /**
4
4
  * Start of the backend's 400 for a registration with an address that already
5
5
  * has an account; the form then links to the password reset.
@@ -55,6 +55,14 @@ export declare function usePasswordAuth({ getValues, onSuccess }: PasswordAuthOp
55
55
  * `registerCustomerWithProfile` action. True once signed in.
56
56
  */
57
57
  registerWithProfile(value: CustomerRegistrationProfileValues): Promise<boolean>;
58
+ /** The partner registration did not submit its application; the account exists. */
59
+ isApplicationNotSubmitted: boolean;
60
+ /**
61
+ * Partner registration with company address; the application follows
62
+ * (after an e-mail confirmation: at the first login). Needs the shop's
63
+ * optional `registerPartnerWithProfile` action. True once signed in.
64
+ */
65
+ registerPartner(value: PartnerRegistrationProfileValues): Promise<boolean>;
58
66
  /** "I confirmed it": signs in again with the kept form values, also after a registration (the account exists by now). */
59
67
  continueAfterVerification(): Promise<void>;
60
68
  };
@@ -75,6 +75,8 @@ export function usePasswordAuth({ getValues, onSuccess }) {
75
75
  const [isContinuing, setIsContinuing] = useState(false);
76
76
  // A registration with profile succeeded but its address could not be stored.
77
77
  const [isAddressNotSaved, setIsAddressNotSaved] = useState(false);
78
+ // A partner registration succeeded but its application could not be submitted.
79
+ const [isApplicationNotSubmitted, setIsApplicationNotSubmitted] = useState(false);
78
80
  // The background check and the "continue" button must not sign in twice.
79
81
  const confirmationSignIn = useRef("idle");
80
82
  async function completeSignIn(sessionToken) {
@@ -162,6 +164,39 @@ export function usePasswordAuth({ getValues, onSuccess }) {
162
164
  return false;
163
165
  }
164
166
  },
167
+ /** The partner registration did not submit its application; the account exists. */
168
+ isApplicationNotSubmitted,
169
+ /**
170
+ * Partner registration with company address; the application follows
171
+ * (after an e-mail confirmation: at the first login). Needs the shop's
172
+ * optional `registerPartnerWithProfile` action. True once signed in.
173
+ */
174
+ async registerPartner(value) {
175
+ const action = actions.registerPartnerWithProfile;
176
+ setErrorMessage(null);
177
+ setIsAddressNotSaved(false);
178
+ setIsApplicationNotSubmitted(false);
179
+ if (!action) {
180
+ setErrorMessage(t("partner_registration.unavailable"));
181
+ return false;
182
+ }
183
+ try {
184
+ const result = unwrapMedusaAction(await action(value));
185
+ if (result.state === "verification_required") {
186
+ setVerification((current) => ({ email: value.email, stillUnverified: current !== null }));
187
+ return false;
188
+ }
189
+ setIsAddressNotSaved(!result.addressSaved);
190
+ setIsApplicationNotSubmitted(!result.applicationSubmitted);
191
+ await completeSignIn(result.sessionToken);
192
+ return true;
193
+ }
194
+ catch (error) {
195
+ setVerification(null);
196
+ setErrorMessage(t.message(getErrorMessage(error, t("auth.sign_in_failed"))));
197
+ return false;
198
+ }
199
+ },
165
200
  /** "I confirmed it": signs in again with the kept form values, also after a registration (the account exists by now). */
166
201
  async continueAfterVerification() {
167
202
  setIsContinuing(true);
@@ -35,25 +35,25 @@ export declare function useCheckoutAddressForm({ countryCode, countryOptions, in
35
35
  shipping_address: {
36
36
  address_1: string;
37
37
  city: string;
38
+ company: string;
38
39
  country_code: string;
39
40
  postal_code: string;
40
41
  first_name: string;
41
42
  last_name: string;
42
43
  phone: string;
43
44
  address_2: string;
44
- company: string;
45
45
  province: string;
46
46
  };
47
47
  billing_address: {
48
48
  address_1: string;
49
49
  city: string;
50
+ company: string;
50
51
  country_code: string;
51
52
  postal_code: string;
52
53
  first_name: string;
53
54
  last_name: string;
54
55
  phone: string;
55
56
  address_2: string;
56
- company: string;
57
57
  province: string;
58
58
  };
59
59
  vat_number: string;
@@ -69,25 +69,25 @@ export declare function useCheckoutAddressForm({ countryCode, countryOptions, in
69
69
  shipping_address: {
70
70
  address_1: string;
71
71
  city: string;
72
+ company: string;
72
73
  country_code: string;
73
74
  postal_code: string;
74
75
  first_name: string;
75
76
  last_name: string;
76
77
  phone: string;
77
78
  address_2: string;
78
- company: string;
79
79
  province: string;
80
80
  };
81
81
  billing_address: {
82
82
  address_1: string;
83
83
  city: string;
84
+ company: string;
84
85
  country_code: string;
85
86
  postal_code: string;
86
87
  first_name: string;
87
88
  last_name: string;
88
89
  phone: string;
89
90
  address_2: string;
90
- company: string;
91
91
  province: string;
92
92
  };
93
93
  vat_number: string;
@@ -105,25 +105,25 @@ export declare function useCheckoutAddressForm({ countryCode, countryOptions, in
105
105
  shipping_address: import("zod").ZodObject<{
106
106
  address_1: import("zod").ZodString;
107
107
  city: import("zod").ZodString;
108
+ company: import("zod").ZodString;
108
109
  country_code: import("zod").ZodString;
109
110
  postal_code: import("zod").ZodString;
110
111
  first_name: import("zod").ZodString;
111
112
  last_name: import("zod").ZodString;
112
113
  phone: import("zod").ZodString;
113
114
  address_2: import("zod").ZodString;
114
- company: import("zod").ZodString;
115
115
  province: import("zod").ZodString;
116
116
  }, import("zod/v4/core").$strip>;
117
117
  billing_address: import("zod").ZodObject<{
118
118
  address_1: import("zod").ZodString;
119
119
  city: import("zod").ZodString;
120
+ company: import("zod").ZodString;
120
121
  country_code: import("zod").ZodString;
121
122
  postal_code: import("zod").ZodString;
122
123
  first_name: import("zod").ZodString;
123
124
  last_name: import("zod").ZodString;
124
125
  phone: import("zod").ZodString;
125
126
  address_2: import("zod").ZodString;
126
- company: import("zod").ZodString;
127
127
  province: import("zod").ZodString;
128
128
  }, import("zod/v4/core").$strip>;
129
129
  vat_number: import("zod").ZodString;
@@ -29,25 +29,25 @@ export declare function useCheckout(countryCode: string): {
29
29
  shipping_address: {
30
30
  address_1: string;
31
31
  city: string;
32
+ company: string;
32
33
  country_code: string;
33
34
  postal_code: string;
34
35
  first_name: string;
35
36
  last_name: string;
36
37
  phone: string;
37
38
  address_2: string;
38
- company: string;
39
39
  province: string;
40
40
  };
41
41
  billing_address: {
42
42
  address_1: string;
43
43
  city: string;
44
+ company: string;
44
45
  country_code: string;
45
46
  postal_code: string;
46
47
  first_name: string;
47
48
  last_name: string;
48
49
  phone: string;
49
50
  address_2: string;
50
- company: string;
51
51
  province: string;
52
52
  };
53
53
  vat_number: string;
@@ -60,25 +60,25 @@ export declare function useCheckout(countryCode: string): {
60
60
  shipping_address: {
61
61
  address_1: string;
62
62
  city: string;
63
+ company: string;
63
64
  country_code: string;
64
65
  postal_code: string;
65
66
  first_name: string;
66
67
  last_name: string;
67
68
  phone: string;
68
69
  address_2: string;
69
- company: string;
70
70
  province: string;
71
71
  };
72
72
  billing_address: {
73
73
  address_1: string;
74
74
  city: string;
75
+ company: string;
75
76
  country_code: string;
76
77
  postal_code: string;
77
78
  first_name: string;
78
79
  last_name: string;
79
80
  phone: string;
80
81
  address_2: string;
81
- company: string;
82
82
  province: string;
83
83
  };
84
84
  vat_number: string;
@@ -4,8 +4,8 @@
4
4
  "title": "Customer account",
5
5
  "description": "Sign-in with password or e-mail code, password reset, account verification, address book with UID check, profile, orders, the account workspace layout and the document download route.",
6
6
  "dependencies": [
7
- "@hartl-services/medusa-storefront@^0.2.0",
8
- "@hartl-services/medusa-contracts@^1.1.0",
7
+ "@hartl-services/medusa-storefront@^0.3.0",
8
+ "@hartl-services/medusa-contracts@^1.2.0",
9
9
  "@medusajs/types@^2.19.0",
10
10
  "lucide-react"
11
11
  ],
@@ -4,8 +4,8 @@
4
4
  "title": "Partner portal",
5
5
  "description": "Partner portal: gated registration with UID check, links, coupon codes, commissions with date filter, consignment reports, and its Route Handlers.",
6
6
  "dependencies": [
7
- "@hartl-services/medusa-storefront@^0.2.0",
8
- "@hartl-services/medusa-contracts@^1.1.0",
7
+ "@hartl-services/medusa-storefront@^0.3.0",
8
+ "@hartl-services/medusa-contracts@^1.2.0",
9
9
  "@medusajs/types@^2.19.0",
10
10
  "lucide-react",
11
11
  "react-day-picker"
@@ -4,7 +4,7 @@
4
4
  "title": "Cart",
5
5
  "description": "Cart widget with popover, line items, totals, cart page, add-to-cart button, variant picker and product price.",
6
6
  "dependencies": [
7
- "@hartl-services/medusa-storefront@^0.2.0",
7
+ "@hartl-services/medusa-storefront@^0.3.0",
8
8
  "@medusajs/types@^2.19.0",
9
9
  "lucide-react"
10
10
  ],
@@ -4,7 +4,7 @@
4
4
  "title": "Checkout",
5
5
  "description": "Checkout page (address, login prompt, shipping and Stripe payment, coupon, UID status) and the order confirmation page.",
6
6
  "dependencies": [
7
- "@hartl-services/medusa-storefront@^0.2.0",
7
+ "@hartl-services/medusa-storefront@^0.3.0",
8
8
  "@medusajs/types@^2.19.0",
9
9
  "@stripe/react-stripe-js@^5.6.1",
10
10
  "@stripe/stripe-js@^8.11.0",
@@ -4,7 +4,7 @@
4
4
  "title": "Storefront form kit",
5
5
  "description": "The shop's TanStack form hook (useAppForm) with unstyled field components; the package's hooks hand their formOptions to it.",
6
6
  "dependencies": [
7
- "@hartl-services/medusa-storefront@^0.2.0",
7
+ "@hartl-services/medusa-storefront@^0.3.0",
8
8
  "@tanstack/react-form@^1.33.5",
9
9
  "input-otp",
10
10
  "lucide-react"