@hartl-services/medusa-storefront 0.2.0 → 0.4.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 +13 -0
- package/dist/browser/actions.d.ts +2 -0
- package/dist/browser/index.d.ts +32 -0
- package/dist/browser/query-options.d.ts +32 -0
- package/dist/core/affiliate/consignment-line-labels.d.ts +19 -0
- package/dist/core/affiliate/consignment-line-labels.js +18 -0
- package/dist/core/catalog/partner-only.d.ts +18 -0
- package/dist/core/catalog/partner-only.js +31 -0
- package/dist/core/form-values.d.ts +51 -2
- package/dist/core/form-values.js +73 -7
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/report-error.d.ts +1 -1
- package/dist/core/texts-de.d.ts +2 -0
- package/dist/core/texts-de.js +2 -0
- package/dist/react/use-affiliate.d.ts +8 -0
- package/dist/react/use-auth.d.ts +9 -1
- package/dist/react/use-auth.js +35 -0
- package/dist/react/use-checkout-address-form.d.ts +6 -6
- package/dist/react/use-checkout.d.ts +4 -4
- package/dist/registry/account.json +2 -2
- package/dist/registry/affiliate.json +4 -4
- package/dist/registry/cart.json +1 -1
- package/dist/registry/checkout.json +1 -1
- package/dist/registry/form.json +1 -1
- package/dist/registry/registry.json +9 -9
- package/dist/registry/setup.json +3 -3
- package/dist/server/affiliate.d.ts +8 -1
- package/dist/server/affiliate.js +29 -0
- package/dist/server/catalog.d.ts +9 -3
- package/dist/server/catalog.js +46 -14
- package/dist/server/customer.d.ts +23 -2
- package/dist/server/customer.js +119 -35
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.js +4 -3
- package/package.json +2 -2
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"];
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -790,6 +790,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
790
790
|
inventory_item_id: string;
|
|
791
791
|
batch_id: string | null;
|
|
792
792
|
expected_quantity: number;
|
|
793
|
+
product_title: string | null;
|
|
794
|
+
variant_title: string | null;
|
|
795
|
+
batch_name: string | null;
|
|
796
|
+
batch_expiry_date: string | null;
|
|
793
797
|
}[];
|
|
794
798
|
}, Error, {
|
|
795
799
|
period_start: string;
|
|
@@ -797,6 +801,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
797
801
|
inventory_item_id: string;
|
|
798
802
|
batch_id: string | null;
|
|
799
803
|
expected_quantity: number;
|
|
804
|
+
product_title: string | null;
|
|
805
|
+
variant_title: string | null;
|
|
806
|
+
batch_name: string | null;
|
|
807
|
+
batch_expiry_date: string | null;
|
|
800
808
|
}[];
|
|
801
809
|
}, readonly ["affiliate", "consignment", "inventory"]>, "queryFn"> & {
|
|
802
810
|
queryFn?: import("@tanstack/react-query").QueryFunction<{
|
|
@@ -805,6 +813,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
805
813
|
inventory_item_id: string;
|
|
806
814
|
batch_id: string | null;
|
|
807
815
|
expected_quantity: number;
|
|
816
|
+
product_title: string | null;
|
|
817
|
+
variant_title: string | null;
|
|
818
|
+
batch_name: string | null;
|
|
819
|
+
batch_expiry_date: string | null;
|
|
808
820
|
}[];
|
|
809
821
|
}, readonly ["affiliate", "consignment", "inventory"], never> | undefined;
|
|
810
822
|
} & import("@tanstack/react-query").QueryKeyWithDataTag<readonly ["affiliate", "consignment", "inventory"], {
|
|
@@ -813,6 +825,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
813
825
|
inventory_item_id: string;
|
|
814
826
|
batch_id: string | null;
|
|
815
827
|
expected_quantity: number;
|
|
828
|
+
product_title: string | null;
|
|
829
|
+
variant_title: string | null;
|
|
830
|
+
batch_name: string | null;
|
|
831
|
+
batch_expiry_date: string | null;
|
|
816
832
|
}[];
|
|
817
833
|
}, Error>;
|
|
818
834
|
affiliateConsignmentReports: () => import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
|
|
@@ -838,6 +854,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
838
854
|
resolved_unit_price: number | null;
|
|
839
855
|
discounted_line_total: number | null;
|
|
840
856
|
currency_code: string | null;
|
|
857
|
+
product_title: string | null;
|
|
858
|
+
variant_title: string | null;
|
|
859
|
+
batch_name: string | null;
|
|
860
|
+
batch_expiry_date: string | null;
|
|
841
861
|
}[];
|
|
842
862
|
}[];
|
|
843
863
|
}, Error, {
|
|
@@ -863,6 +883,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
863
883
|
resolved_unit_price: number | null;
|
|
864
884
|
discounted_line_total: number | null;
|
|
865
885
|
currency_code: string | null;
|
|
886
|
+
product_title: string | null;
|
|
887
|
+
variant_title: string | null;
|
|
888
|
+
batch_name: string | null;
|
|
889
|
+
batch_expiry_date: string | null;
|
|
866
890
|
}[];
|
|
867
891
|
}[];
|
|
868
892
|
}, readonly ["affiliate", "consignment", "reports"]>, "queryFn"> & {
|
|
@@ -889,6 +913,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
889
913
|
resolved_unit_price: number | null;
|
|
890
914
|
discounted_line_total: number | null;
|
|
891
915
|
currency_code: string | null;
|
|
916
|
+
product_title: string | null;
|
|
917
|
+
variant_title: string | null;
|
|
918
|
+
batch_name: string | null;
|
|
919
|
+
batch_expiry_date: string | null;
|
|
892
920
|
}[];
|
|
893
921
|
}[];
|
|
894
922
|
}, readonly ["affiliate", "consignment", "reports"], never> | undefined;
|
|
@@ -915,6 +943,10 @@ export declare function createStorefrontBrowser(config: StorefrontBrowserConfig)
|
|
|
915
943
|
resolved_unit_price: number | null;
|
|
916
944
|
discounted_line_total: number | null;
|
|
917
945
|
currency_code: string | null;
|
|
946
|
+
product_title: string | null;
|
|
947
|
+
variant_title: string | null;
|
|
948
|
+
batch_name: string | null;
|
|
949
|
+
batch_expiry_date: string | null;
|
|
918
950
|
}[];
|
|
919
951
|
}[];
|
|
920
952
|
}, Error>;
|
|
@@ -648,6 +648,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
648
648
|
inventory_item_id: string;
|
|
649
649
|
batch_id: string | null;
|
|
650
650
|
expected_quantity: number;
|
|
651
|
+
product_title: string | null;
|
|
652
|
+
variant_title: string | null;
|
|
653
|
+
batch_name: string | null;
|
|
654
|
+
batch_expiry_date: string | null;
|
|
651
655
|
}[];
|
|
652
656
|
}, Error, {
|
|
653
657
|
period_start: string;
|
|
@@ -655,6 +659,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
655
659
|
inventory_item_id: string;
|
|
656
660
|
batch_id: string | null;
|
|
657
661
|
expected_quantity: number;
|
|
662
|
+
product_title: string | null;
|
|
663
|
+
variant_title: string | null;
|
|
664
|
+
batch_name: string | null;
|
|
665
|
+
batch_expiry_date: string | null;
|
|
658
666
|
}[];
|
|
659
667
|
}, readonly ["affiliate", "consignment", "inventory"]>, "queryFn"> & {
|
|
660
668
|
queryFn?: import("@tanstack/react-query").QueryFunction<{
|
|
@@ -663,6 +671,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
663
671
|
inventory_item_id: string;
|
|
664
672
|
batch_id: string | null;
|
|
665
673
|
expected_quantity: number;
|
|
674
|
+
product_title: string | null;
|
|
675
|
+
variant_title: string | null;
|
|
676
|
+
batch_name: string | null;
|
|
677
|
+
batch_expiry_date: string | null;
|
|
666
678
|
}[];
|
|
667
679
|
}, readonly ["affiliate", "consignment", "inventory"], never> | undefined;
|
|
668
680
|
} & import("@tanstack/react-query").QueryKeyWithDataTag<readonly ["affiliate", "consignment", "inventory"], {
|
|
@@ -671,6 +683,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
671
683
|
inventory_item_id: string;
|
|
672
684
|
batch_id: string | null;
|
|
673
685
|
expected_quantity: number;
|
|
686
|
+
product_title: string | null;
|
|
687
|
+
variant_title: string | null;
|
|
688
|
+
batch_name: string | null;
|
|
689
|
+
batch_expiry_date: string | null;
|
|
674
690
|
}[];
|
|
675
691
|
}, Error>;
|
|
676
692
|
affiliateConsignmentReports: () => import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
|
|
@@ -696,6 +712,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
696
712
|
resolved_unit_price: number | null;
|
|
697
713
|
discounted_line_total: number | null;
|
|
698
714
|
currency_code: string | null;
|
|
715
|
+
product_title: string | null;
|
|
716
|
+
variant_title: string | null;
|
|
717
|
+
batch_name: string | null;
|
|
718
|
+
batch_expiry_date: string | null;
|
|
699
719
|
}[];
|
|
700
720
|
}[];
|
|
701
721
|
}, Error, {
|
|
@@ -721,6 +741,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
721
741
|
resolved_unit_price: number | null;
|
|
722
742
|
discounted_line_total: number | null;
|
|
723
743
|
currency_code: string | null;
|
|
744
|
+
product_title: string | null;
|
|
745
|
+
variant_title: string | null;
|
|
746
|
+
batch_name: string | null;
|
|
747
|
+
batch_expiry_date: string | null;
|
|
724
748
|
}[];
|
|
725
749
|
}[];
|
|
726
750
|
}, readonly ["affiliate", "consignment", "reports"]>, "queryFn"> & {
|
|
@@ -747,6 +771,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
747
771
|
resolved_unit_price: number | null;
|
|
748
772
|
discounted_line_total: number | null;
|
|
749
773
|
currency_code: string | null;
|
|
774
|
+
product_title: string | null;
|
|
775
|
+
variant_title: string | null;
|
|
776
|
+
batch_name: string | null;
|
|
777
|
+
batch_expiry_date: string | null;
|
|
750
778
|
}[];
|
|
751
779
|
}[];
|
|
752
780
|
}, readonly ["affiliate", "consignment", "reports"], never> | undefined;
|
|
@@ -773,6 +801,10 @@ export declare function createQueryOptions({ actions, affiliateApiPaths, cart, r
|
|
|
773
801
|
resolved_unit_price: number | null;
|
|
774
802
|
discounted_line_total: number | null;
|
|
775
803
|
currency_code: string | null;
|
|
804
|
+
product_title: string | null;
|
|
805
|
+
variant_title: string | null;
|
|
806
|
+
batch_name: string | null;
|
|
807
|
+
batch_expiry_date: string | null;
|
|
776
808
|
}[];
|
|
777
809
|
}[];
|
|
778
810
|
}, Error>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ConsignmentLineLabels } from "@hartl-services/medusa-contracts/types/affiliate-store";
|
|
2
|
+
/**
|
|
3
|
+
* Display parts of a consignment line (stock line or report line). The ids
|
|
4
|
+
* stay the fallback while a product or batch cannot be resolved; the shop
|
|
5
|
+
* puts the parts into its own wording.
|
|
6
|
+
*/
|
|
7
|
+
export interface ConsignmentLineDisplay {
|
|
8
|
+
/** "Product – Variant", the product alone, or null without a product. */
|
|
9
|
+
product: string | null;
|
|
10
|
+
/** Batch name, or the batch id while the name is unknown; null without batch. */
|
|
11
|
+
batch: string | null;
|
|
12
|
+
/** Expiry date as written for `locale`, or null. */
|
|
13
|
+
expiryDate: string | null;
|
|
14
|
+
}
|
|
15
|
+
export type ConsignmentLineDisplayInput = Partial<ConsignmentLineLabels> & {
|
|
16
|
+
inventory_item_id: string;
|
|
17
|
+
batch_id: string | null;
|
|
18
|
+
};
|
|
19
|
+
export declare function getConsignmentLineDisplay(line: ConsignmentLineDisplayInput, locale: string): ConsignmentLineDisplay;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function getConsignmentLineDisplay(line, locale) {
|
|
2
|
+
const product = line.product_title?.trim() || null;
|
|
3
|
+
const variant = line.variant_title?.trim() || null;
|
|
4
|
+
const productLabel = product && variant && variant !== product ? `${product} – ${variant}` : (product ?? variant);
|
|
5
|
+
return {
|
|
6
|
+
product: productLabel,
|
|
7
|
+
batch: line.batch_id ? line.batch_name?.trim() || line.batch_id : null,
|
|
8
|
+
expiryDate: line.batch_id && line.batch_expiry_date ? formatCalendarDate(line.batch_expiry_date, locale) : null,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
// A calendar date (YYYY-MM-DD) has no time zone; formatting it in UTC keeps
|
|
12
|
+
// the day the backend sent.
|
|
13
|
+
function formatCalendarDate(value, locale) {
|
|
14
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
15
|
+
return Number.isNaN(date.getTime())
|
|
16
|
+
? value
|
|
17
|
+
: new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric", timeZone: "UTC" }).format(date);
|
|
18
|
+
}
|
|
@@ -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>>;
|
package/dist/core/form-values.js
CHANGED
|
@@ -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
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
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);
|
package/dist/core/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./affiliate/affiliate-coupon-code-presentation.js";
|
|
|
5
5
|
export * from "./affiliate/affiliate-coupon-label.js";
|
|
6
6
|
export * from "./affiliate/affiliate-date-range.js";
|
|
7
7
|
export * from "./affiliate/affiliate-rate-presentation.js";
|
|
8
|
+
export * from "./affiliate/consignment-line-labels.js";
|
|
8
9
|
export * from "./affiliate/partner-company-address.js";
|
|
9
10
|
export * from "./auth/customer-sign-in.js";
|
|
10
11
|
export * from "./auth/link-token.js";
|
|
@@ -18,6 +19,7 @@ export * from "./cart/coupon-promotions.js";
|
|
|
18
19
|
export * from "./cart/payment-session.js";
|
|
19
20
|
export * from "./cart/refunded-cart.js";
|
|
20
21
|
export * from "./catalog/category-filter.js";
|
|
22
|
+
export * from "./catalog/partner-only.js";
|
|
21
23
|
export * from "./catalog/inventory.js";
|
|
22
24
|
export * from "./catalog/medusa-product-image.js";
|
|
23
25
|
export * from "./catalog/product-price.js";
|
package/dist/core/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./affiliate/affiliate-coupon-code-presentation.js";
|
|
|
6
6
|
export * from "./affiliate/affiliate-coupon-label.js";
|
|
7
7
|
export * from "./affiliate/affiliate-date-range.js";
|
|
8
8
|
export * from "./affiliate/affiliate-rate-presentation.js";
|
|
9
|
+
export * from "./affiliate/consignment-line-labels.js";
|
|
9
10
|
export * from "./affiliate/partner-company-address.js";
|
|
10
11
|
export * from "./auth/customer-sign-in.js";
|
|
11
12
|
export * from "./auth/link-token.js";
|
|
@@ -19,6 +20,7 @@ export * from "./cart/coupon-promotions.js";
|
|
|
19
20
|
export * from "./cart/payment-session.js";
|
|
20
21
|
export * from "./cart/refunded-cart.js";
|
|
21
22
|
export * from "./catalog/category-filter.js";
|
|
23
|
+
export * from "./catalog/partner-only.js";
|
|
22
24
|
export * from "./catalog/inventory.js";
|
|
23
25
|
export * from "./catalog/medusa-product-image.js";
|
|
24
26
|
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. */
|
package/dist/core/texts-de.d.ts
CHANGED
|
@@ -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.";
|
package/dist/core/texts-de.js
CHANGED
|
@@ -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.",
|
|
@@ -513,6 +513,10 @@ export declare function useAffiliateConsignment(): {
|
|
|
513
513
|
inventory_item_id: string;
|
|
514
514
|
batch_id: string | null;
|
|
515
515
|
expected_quantity: number;
|
|
516
|
+
product_title: string | null;
|
|
517
|
+
variant_title: string | null;
|
|
518
|
+
batch_name: string | null;
|
|
519
|
+
batch_expiry_date: string | null;
|
|
516
520
|
}[];
|
|
517
521
|
}, Error>;
|
|
518
522
|
isActive: boolean;
|
|
@@ -540,6 +544,10 @@ export declare function useAffiliateConsignment(): {
|
|
|
540
544
|
resolved_unit_price: number | null;
|
|
541
545
|
discounted_line_total: number | null;
|
|
542
546
|
currency_code: string | null;
|
|
547
|
+
product_title: string | null;
|
|
548
|
+
variant_title: string | null;
|
|
549
|
+
batch_name: string | null;
|
|
550
|
+
batch_expiry_date: string | null;
|
|
543
551
|
}[];
|
|
544
552
|
}[];
|
|
545
553
|
}, Error>;
|
package/dist/react/use-auth.d.ts
CHANGED
|
@@ -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
|
};
|