@pvh-afl/graphql 1.1.22 → 1.1.24
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/customer/customer.resolver.d.ts +3 -1
- package/dist/customer/customer.resolver.d.ts.map +1 -1
- package/dist/customer/customer.resolver.js +54 -0
- package/dist/customer/customer.resolver.js.map +1 -1
- package/dist/customer/customer.service.d.ts +31 -3
- package/dist/customer/customer.service.d.ts.map +1 -1
- package/dist/customer/customer.service.js +86 -10
- package/dist/customer/customer.service.js.map +1 -1
- package/dist/customer/customer.types.d.ts +11 -1
- package/dist/customer/customer.types.d.ts.map +1 -1
- package/dist/customer/customer.types.js +50 -2
- package/dist/customer/customer.types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CustomerService } from './customer.service';
|
|
2
|
-
import { CustomerLoginResult } from './customer.types';
|
|
2
|
+
import { Customer, CustomerLoginResult, CustomerUpdateInput } from './customer.types';
|
|
3
3
|
interface GqlContext {
|
|
4
4
|
req: {
|
|
5
5
|
brand: string;
|
|
@@ -9,7 +9,9 @@ interface GqlContext {
|
|
|
9
9
|
export declare class CustomerResolver {
|
|
10
10
|
private readonly customerService;
|
|
11
11
|
constructor(customerService: CustomerService);
|
|
12
|
+
customer(ctx: GqlContext, customerAccessToken: string): Promise<Customer | null>;
|
|
12
13
|
customerLogin(ctx: GqlContext, email: string, password: string): Promise<CustomerLoginResult>;
|
|
14
|
+
customerUpdate(ctx: GqlContext, customerAccessToken: string, input: CustomerUpdateInput): Promise<Customer>;
|
|
13
15
|
}
|
|
14
16
|
export {};
|
|
15
17
|
//# sourceMappingURL=customer.resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customer.resolver.d.ts","sourceRoot":"","sources":["../../src/customer/customer.resolver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"customer.resolver.d.ts","sourceRoot":"","sources":["../../src/customer/customer.resolver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,UAAU,UAAU;IAClB,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBACa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAAf,eAAe,EAAE,eAAe;IAavD,QAAQ,CACD,GAAG,EAAE,UAAU,EAK1B,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAkBrB,aAAa,CACN,GAAG,EAAE,UAAU,EAE1B,KAAK,EAAE,MAAM,EAEb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC;IAgBzB,cAAc,CACP,GAAG,EAAE,UAAU,EAK1B,mBAAmB,EAAE,MAAM,EAK3B,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,QAAQ,CAAC;CAIrB"}
|
|
@@ -12,12 +12,41 @@ let CustomerResolver = class CustomerResolver {
|
|
|
12
12
|
constructor(customerService) {
|
|
13
13
|
this.customerService = customerService;
|
|
14
14
|
}
|
|
15
|
+
async customer(ctx, customerAccessToken) {
|
|
16
|
+
const brand = ctx.brand ?? ctx.req.brand;
|
|
17
|
+
return this.customerService.getProfile(brand, customerAccessToken);
|
|
18
|
+
}
|
|
15
19
|
async customerLogin(ctx, email, password) {
|
|
16
20
|
const brand = ctx.brand ?? ctx.req.brand;
|
|
17
21
|
return this.customerService.login(brand, email, password);
|
|
18
22
|
}
|
|
23
|
+
async customerUpdate(ctx, customerAccessToken, input) {
|
|
24
|
+
const brand = ctx.brand ?? ctx.req.brand;
|
|
25
|
+
return this.customerService.updateProfile(brand, customerAccessToken, input);
|
|
26
|
+
}
|
|
19
27
|
};
|
|
20
28
|
exports.CustomerResolver = CustomerResolver;
|
|
29
|
+
tslib_1.__decorate([
|
|
30
|
+
(0, graphql_1.Query)(() => customer_types_1.Customer, {
|
|
31
|
+
nullable: true,
|
|
32
|
+
description: `Fetch the customer's profile (including gender and birthDate)
|
|
33
|
+
from a Storefront customerAccessToken.
|
|
34
|
+
|
|
35
|
+
Use this to rehydrate the profile from a stored token without re-authenticating
|
|
36
|
+
(e.g. on app reload or when opening the profile screen). Returns null if the
|
|
37
|
+
token is missing, invalid, or expired — the frontend can treat null as a
|
|
38
|
+
"session expired" signal and route the user back to login.`,
|
|
39
|
+
}),
|
|
40
|
+
(0, common_1.UseGuards)(core_1.TenantGuard),
|
|
41
|
+
tslib_1.__param(0, (0, graphql_1.Context)()),
|
|
42
|
+
tslib_1.__param(1, (0, graphql_1.Args)('customerAccessToken', {
|
|
43
|
+
type: () => String,
|
|
44
|
+
description: 'Storefront customer access token from customerLogin',
|
|
45
|
+
})),
|
|
46
|
+
tslib_1.__metadata("design:type", Function),
|
|
47
|
+
tslib_1.__metadata("design:paramtypes", [Object, String]),
|
|
48
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
49
|
+
], CustomerResolver.prototype, "customer", null);
|
|
21
50
|
tslib_1.__decorate([
|
|
22
51
|
(0, graphql_1.Mutation)(() => customer_types_1.CustomerLoginResult, {
|
|
23
52
|
description: `Log a customer in with email and password.
|
|
@@ -39,6 +68,31 @@ Capillary coupons to apply).`,
|
|
|
39
68
|
tslib_1.__metadata("design:paramtypes", [Object, String, String]),
|
|
40
69
|
tslib_1.__metadata("design:returntype", Promise)
|
|
41
70
|
], CustomerResolver.prototype, "customerLogin", null);
|
|
71
|
+
tslib_1.__decorate([
|
|
72
|
+
(0, graphql_1.Mutation)(() => customer_types_1.Customer, {
|
|
73
|
+
description: `Update the logged-in customer's profile facts (gender, birthDate).
|
|
74
|
+
|
|
75
|
+
The customer is identified by their Storefront customerAccessToken (from
|
|
76
|
+
customerLogin) — this proves account ownership. Only the fields provided in
|
|
77
|
+
input are updated; omitted fields are left unchanged. Values are written to the
|
|
78
|
+
facts.gender / facts.birth_date customer metafields via the Shopify Admin API.
|
|
79
|
+
|
|
80
|
+
Returns the updated customer.`,
|
|
81
|
+
}),
|
|
82
|
+
(0, common_1.UseGuards)(core_1.TenantGuard),
|
|
83
|
+
tslib_1.__param(0, (0, graphql_1.Context)()),
|
|
84
|
+
tslib_1.__param(1, (0, graphql_1.Args)('customerAccessToken', {
|
|
85
|
+
type: () => String,
|
|
86
|
+
description: 'Storefront customer access token from customerLogin',
|
|
87
|
+
})),
|
|
88
|
+
tslib_1.__param(2, (0, graphql_1.Args)('input', {
|
|
89
|
+
type: () => customer_types_1.CustomerUpdateInput,
|
|
90
|
+
description: 'Profile fields to update',
|
|
91
|
+
})),
|
|
92
|
+
tslib_1.__metadata("design:type", Function),
|
|
93
|
+
tslib_1.__metadata("design:paramtypes", [Object, String, customer_types_1.CustomerUpdateInput]),
|
|
94
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
95
|
+
], CustomerResolver.prototype, "customerUpdate", null);
|
|
42
96
|
exports.CustomerResolver = CustomerResolver = tslib_1.__decorate([
|
|
43
97
|
(0, graphql_1.Resolver)(),
|
|
44
98
|
tslib_1.__metadata("design:paramtypes", [customer_service_1.CustomerService])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customer.resolver.js","sourceRoot":"","sources":["../../src/customer/customer.resolver.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"customer.resolver.js","sourceRoot":"","sources":["../../src/customer/customer.resolver.ts"],"names":[],"mappings":";;;;AAAA,6CAA2E;AAC3E,2CAA2C;AAC3C,wCAA4C;AAC5C,yDAAqD;AACrD,qDAAsF;AAQ/E,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACE;IAA7B,YAA6B,eAAgC;QAAhC,oBAAe,GAAf,eAAe,CAAiB;IAAG,CAAC;IAa3D,AAAN,KAAK,CAAC,QAAQ,CACD,GAAe,EAK1B,mBAA2B;QAE3B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;QACzC,OAAO,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAeK,AAAN,KAAK,CAAC,aAAa,CACN,GAAe,EAE1B,KAAa,EAEb,QAAgB;QAEhB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;QACzC,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAaK,AAAN,KAAK,CAAC,cAAc,CACP,GAAe,EAK1B,mBAA2B,EAK3B,KAA0B;QAE1B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;QACzC,OAAO,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAC/E,CAAC;CACF,CAAA;AA7EY,4CAAgB;AAcrB;IAXL,IAAA,eAAK,EAAC,GAAG,EAAE,CAAC,yBAAQ,EAAE;QACrB,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE;;;;;;2DAM0C;KACxD,CAAC;IACD,IAAA,kBAAS,EAAC,kBAAW,CAAC;IAEpB,mBAAA,IAAA,iBAAO,GAAE,CAAA;IACT,mBAAA,IAAA,cAAI,EAAC,qBAAqB,EAAE;QAC3B,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM;QAClB,WAAW,EAAE,qDAAqD;KACnE,CAAC,CAAA;;;;gDAKH;AAeK;IAbL,IAAA,kBAAQ,EAAC,GAAG,EAAE,CAAC,oCAAmB,EAAE;QACnC,WAAW,EAAE;;;;;;;;;6BASY;KAC1B,CAAC;IACD,IAAA,kBAAS,EAAC,kBAAW,CAAC;IAEpB,mBAAA,IAAA,iBAAO,GAAE,CAAA;IACT,mBAAA,IAAA,cAAI,EAAC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,CAAA;IAEpE,mBAAA,IAAA,cAAI,EAAC,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAA;;;;qDAK5E;AAaK;IAXL,IAAA,kBAAQ,EAAC,GAAG,EAAE,CAAC,yBAAQ,EAAE;QACxB,WAAW,EAAE;;;;;;;8BAOa;KAC3B,CAAC;IACD,IAAA,kBAAS,EAAC,kBAAW,CAAC;IAEpB,mBAAA,IAAA,iBAAO,GAAE,CAAA;IACT,mBAAA,IAAA,cAAI,EAAC,qBAAqB,EAAE;QAC3B,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM;QAClB,WAAW,EAAE,qDAAqD;KACnE,CAAC,CAAA;IAED,mBAAA,IAAA,cAAI,EAAC,OAAO,EAAE;QACb,IAAI,EAAE,GAAG,EAAE,CAAC,oCAAmB;QAC/B,WAAW,EAAE,0BAA0B;KACxC,CAAC,CAAA;;6DACK,oCAAmB;;sDAI3B;2BA5EU,gBAAgB;IAD5B,IAAA,kBAAQ,GAAE;6CAEqC,kCAAe;GADlD,gBAAgB,CA6E5B"}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import { IntegrationFactory } from '@pvh-afl/core';
|
|
2
|
-
import { CustomerLoginResult } from './customer.types';
|
|
1
|
+
import { IntegrationFactory, ShopifyAdminService } from '@pvh-afl/core';
|
|
2
|
+
import { Customer, CustomerLoginResult, CustomerUpdateInput } from './customer.types';
|
|
3
3
|
export declare class CustomerService {
|
|
4
4
|
private readonly integrationFactory;
|
|
5
|
-
|
|
5
|
+
private readonly adminService;
|
|
6
|
+
constructor(integrationFactory: IntegrationFactory, adminService: ShopifyAdminService);
|
|
6
7
|
private getCommerceService;
|
|
8
|
+
/**
|
|
9
|
+
* Map a raw metafield gender value onto the Gender enum. Returns undefined for
|
|
10
|
+
* missing or unrecognised values so we never emit an invalid enum.
|
|
11
|
+
*/
|
|
12
|
+
private toGender;
|
|
13
|
+
/**
|
|
14
|
+
* Map a Storefront customer plus its Admin-API "facts" onto the GraphQL
|
|
15
|
+
* Customer type.
|
|
16
|
+
*/
|
|
17
|
+
private toCustomer;
|
|
7
18
|
/**
|
|
8
19
|
* Log a customer in with email + password.
|
|
9
20
|
*
|
|
@@ -14,5 +25,22 @@ export declare class CustomerService {
|
|
|
14
25
|
* cartBuyerIdentityUpdate) together with the customer.
|
|
15
26
|
*/
|
|
16
27
|
login(brand: string, email: string, password: string): Promise<CustomerLoginResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Fetch a customer's profile from a Storefront access token.
|
|
30
|
+
*
|
|
31
|
+
* Lets the frontend rehydrate the profile (including gender / birth_date)
|
|
32
|
+
* from a stored token without re-authenticating. Returns null if the token
|
|
33
|
+
* is missing, invalid, or expired so the caller can treat it as a
|
|
34
|
+
* "session expired" signal.
|
|
35
|
+
*/
|
|
36
|
+
getProfile(brand: string, customerAccessToken: string): Promise<Customer | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Update the logged-in customer's profile "facts" (gender, birth_date).
|
|
39
|
+
*
|
|
40
|
+
* The customer is identified by their Storefront access token: we resolve the
|
|
41
|
+
* token to a customer (proving ownership) and then write the metafields via
|
|
42
|
+
* the Admin API. Returns the updated customer.
|
|
43
|
+
*/
|
|
44
|
+
updateProfile(brand: string, customerAccessToken: string, input: CustomerUpdateInput): Promise<Customer>;
|
|
17
45
|
}
|
|
18
46
|
//# sourceMappingURL=customer.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customer.service.d.ts","sourceRoot":"","sources":["../../src/customer/customer.service.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"customer.service.d.ts","sourceRoot":"","sources":["../../src/customer/customer.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAGlB,mBAAmB,EAGpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,mBAAmB,EAEpB,MAAM,kBAAkB,CAAC;AAE1B,qBACa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,mBAAmB;IAGpD,OAAO,CAAC,kBAAkB;IAQ1B;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAOhB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAalB;;;;;;;;OAQG;IACG,KAAK,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC;IAsC/B;;;;;;;OAOG;IACG,UAAU,CACd,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAkB3B;;;;;;OAMG;IACG,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,MAAM,EAC3B,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,QAAQ,CAAC;CAkCrB"}
|
|
@@ -4,10 +4,13 @@ exports.CustomerService = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const common_1 = require("@nestjs/common");
|
|
6
6
|
const core_1 = require("@pvh-afl/core");
|
|
7
|
+
const customer_types_1 = require("./customer.types");
|
|
7
8
|
let CustomerService = class CustomerService {
|
|
8
9
|
integrationFactory;
|
|
9
|
-
|
|
10
|
+
adminService;
|
|
11
|
+
constructor(integrationFactory, adminService) {
|
|
10
12
|
this.integrationFactory = integrationFactory;
|
|
13
|
+
this.adminService = adminService;
|
|
11
14
|
}
|
|
12
15
|
getCommerceService(brand) {
|
|
13
16
|
const commerce = this.integrationFactory.get(brand, 'commerce');
|
|
@@ -16,6 +19,32 @@ let CustomerService = class CustomerService {
|
|
|
16
19
|
}
|
|
17
20
|
return commerce;
|
|
18
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Map a raw metafield gender value onto the Gender enum. Returns undefined for
|
|
24
|
+
* missing or unrecognised values so we never emit an invalid enum.
|
|
25
|
+
*/
|
|
26
|
+
toGender(value) {
|
|
27
|
+
if (value === customer_types_1.Gender.Male || value === customer_types_1.Gender.Female) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Map a Storefront customer plus its Admin-API "facts" onto the GraphQL
|
|
34
|
+
* Customer type.
|
|
35
|
+
*/
|
|
36
|
+
toCustomer(customer, facts) {
|
|
37
|
+
return {
|
|
38
|
+
id: customer.id,
|
|
39
|
+
email: customer.email ?? undefined,
|
|
40
|
+
firstName: customer.firstName ?? undefined,
|
|
41
|
+
lastName: customer.lastName ?? undefined,
|
|
42
|
+
phone: customer.phone ?? undefined,
|
|
43
|
+
displayName: customer.displayName,
|
|
44
|
+
gender: this.toGender(facts.gender),
|
|
45
|
+
birthDate: facts.birthDate,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
19
48
|
/**
|
|
20
49
|
* Log a customer in with email + password.
|
|
21
50
|
*
|
|
@@ -43,24 +72,71 @@ let CustomerService = class CustomerService {
|
|
|
43
72
|
throw new Error(customerResult.error?.message ?? 'Failed to fetch customer details');
|
|
44
73
|
}
|
|
45
74
|
const customer = customerResult.data;
|
|
75
|
+
// Fetch profile "facts" (gender, birth_date) via the Admin API. The
|
|
76
|
+
// Storefront customer query does not expose these custom metafields.
|
|
77
|
+
const facts = await this.adminService.getCustomerFacts(brand, customer.id);
|
|
46
78
|
core_1.logger.info('Customer logged in', { brand, customerId: customer.id });
|
|
47
79
|
return {
|
|
48
80
|
customerAccessToken: accessToken,
|
|
49
81
|
expiresAt,
|
|
50
|
-
customer:
|
|
51
|
-
id: customer.id,
|
|
52
|
-
email: customer.email ?? undefined,
|
|
53
|
-
firstName: customer.firstName ?? undefined,
|
|
54
|
-
lastName: customer.lastName ?? undefined,
|
|
55
|
-
phone: customer.phone ?? undefined,
|
|
56
|
-
displayName: customer.displayName,
|
|
57
|
-
},
|
|
82
|
+
customer: this.toCustomer(customer, facts),
|
|
58
83
|
};
|
|
59
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Fetch a customer's profile from a Storefront access token.
|
|
87
|
+
*
|
|
88
|
+
* Lets the frontend rehydrate the profile (including gender / birth_date)
|
|
89
|
+
* from a stored token without re-authenticating. Returns null if the token
|
|
90
|
+
* is missing, invalid, or expired so the caller can treat it as a
|
|
91
|
+
* "session expired" signal.
|
|
92
|
+
*/
|
|
93
|
+
async getProfile(brand, customerAccessToken) {
|
|
94
|
+
const commerce = this.getCommerceService(brand);
|
|
95
|
+
const customerResult = await commerce.getCustomer(customerAccessToken);
|
|
96
|
+
if (!customerResult.success || !customerResult.data) {
|
|
97
|
+
core_1.logger.info('Customer profile fetch failed (invalid/expired token)', {
|
|
98
|
+
brand,
|
|
99
|
+
errorCode: customerResult.error?.code,
|
|
100
|
+
});
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const customer = customerResult.data;
|
|
104
|
+
const facts = await this.adminService.getCustomerFacts(brand, customer.id);
|
|
105
|
+
return this.toCustomer(customer, facts);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Update the logged-in customer's profile "facts" (gender, birth_date).
|
|
109
|
+
*
|
|
110
|
+
* The customer is identified by their Storefront access token: we resolve the
|
|
111
|
+
* token to a customer (proving ownership) and then write the metafields via
|
|
112
|
+
* the Admin API. Returns the updated customer.
|
|
113
|
+
*/
|
|
114
|
+
async updateProfile(brand, customerAccessToken, input) {
|
|
115
|
+
const commerce = this.getCommerceService(brand);
|
|
116
|
+
// Resolve the token to a customer — this proves the caller owns the account.
|
|
117
|
+
const customerResult = await commerce.getCustomer(customerAccessToken);
|
|
118
|
+
if (!customerResult.success || !customerResult.data) {
|
|
119
|
+
throw new Error(customerResult.error?.message ?? 'Invalid or expired customer access token');
|
|
120
|
+
}
|
|
121
|
+
const customer = customerResult.data;
|
|
122
|
+
const facts = {
|
|
123
|
+
gender: input.gender,
|
|
124
|
+
birthDate: input.birthDate,
|
|
125
|
+
};
|
|
126
|
+
const updateResult = await this.adminService.updateCustomerFacts(brand, customer.id, facts);
|
|
127
|
+
if (!updateResult.success) {
|
|
128
|
+
throw new Error(updateResult.error ?? 'Failed to update customer profile');
|
|
129
|
+
}
|
|
130
|
+
// Re-read the facts so the response reflects the persisted state.
|
|
131
|
+
const updatedFacts = await this.adminService.getCustomerFacts(brand, customer.id);
|
|
132
|
+
core_1.logger.info('Customer profile updated', { brand, customerId: customer.id });
|
|
133
|
+
return this.toCustomer(customer, updatedFacts);
|
|
134
|
+
}
|
|
60
135
|
};
|
|
61
136
|
exports.CustomerService = CustomerService;
|
|
62
137
|
exports.CustomerService = CustomerService = tslib_1.__decorate([
|
|
63
138
|
(0, common_1.Injectable)(),
|
|
64
|
-
tslib_1.__metadata("design:paramtypes", [core_1.IntegrationFactory
|
|
139
|
+
tslib_1.__metadata("design:paramtypes", [core_1.IntegrationFactory,
|
|
140
|
+
core_1.ShopifyAdminService])
|
|
65
141
|
], CustomerService);
|
|
66
142
|
//# sourceMappingURL=customer.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customer.service.js","sourceRoot":"","sources":["../../src/customer/customer.service.ts"],"names":[],"mappings":";;;;AAAA,2CAA4C;AAC5C,
|
|
1
|
+
{"version":3,"file":"customer.service.js","sourceRoot":"","sources":["../../src/customer/customer.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GraphQL Types for Customer authentication.
|
|
2
|
+
* GraphQL Types for Customer authentication and profile.
|
|
3
3
|
*/
|
|
4
|
+
export declare enum Gender {
|
|
5
|
+
Male = "Male",
|
|
6
|
+
Female = "Female"
|
|
7
|
+
}
|
|
4
8
|
export declare class Customer {
|
|
5
9
|
id: string;
|
|
6
10
|
email?: string;
|
|
@@ -8,6 +12,12 @@ export declare class Customer {
|
|
|
8
12
|
lastName?: string;
|
|
9
13
|
phone?: string;
|
|
10
14
|
displayName: string;
|
|
15
|
+
gender?: Gender;
|
|
16
|
+
birthDate?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class CustomerUpdateInput {
|
|
19
|
+
gender?: Gender;
|
|
20
|
+
birthDate?: string;
|
|
11
21
|
}
|
|
12
22
|
export declare class CustomerLoginResult {
|
|
13
23
|
customerAccessToken: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customer.types.d.ts","sourceRoot":"","sources":["../../src/customer/customer.types.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,qBACa,QAAQ;IAEnB,EAAE,EAAG,MAAM,CAAC;IAGZ,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,WAAW,EAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"customer.types.d.ts","sourceRoot":"","sources":["../../src/customer/customer.types.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,oBAAY,MAAM;IAChB,IAAI,SAAS;IACb,MAAM,WAAW;CAClB;AAWD,qBACa,QAAQ;IAEnB,EAAE,EAAG,MAAM,CAAC;IAGZ,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,WAAW,EAAG,MAAM,CAAC;IAMrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAOhB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBACa,mBAAmB;IAE9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAMhB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAIa,mBAAmB;IAK9B,mBAAmB,EAAG,MAAM,CAAC;IAG7B,SAAS,EAAG,MAAM,CAAC;IAGnB,QAAQ,EAAG,QAAQ,CAAC;CACrB"}
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CustomerLoginResult = exports.Customer = void 0;
|
|
3
|
+
exports.CustomerLoginResult = exports.CustomerUpdateInput = exports.Customer = exports.Gender = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const graphql_1 = require("@nestjs/graphql");
|
|
6
6
|
/**
|
|
7
|
-
* GraphQL Types for Customer authentication.
|
|
7
|
+
* GraphQL Types for Customer authentication and profile.
|
|
8
8
|
*/
|
|
9
|
+
var Gender;
|
|
10
|
+
(function (Gender) {
|
|
11
|
+
Gender["Male"] = "Male";
|
|
12
|
+
Gender["Female"] = "Female";
|
|
13
|
+
})(Gender || (exports.Gender = Gender = {}));
|
|
14
|
+
(0, graphql_1.registerEnumType)(Gender, {
|
|
15
|
+
name: 'Gender',
|
|
16
|
+
description: 'Customer gender (stored in the facts.gender metafield).',
|
|
17
|
+
valuesMap: {
|
|
18
|
+
Male: { description: 'Male' },
|
|
19
|
+
Female: { description: 'Female' },
|
|
20
|
+
},
|
|
21
|
+
});
|
|
9
22
|
let Customer = class Customer {
|
|
10
23
|
id;
|
|
11
24
|
email;
|
|
@@ -13,6 +26,8 @@ let Customer = class Customer {
|
|
|
13
26
|
lastName;
|
|
14
27
|
phone;
|
|
15
28
|
displayName;
|
|
29
|
+
gender;
|
|
30
|
+
birthDate;
|
|
16
31
|
};
|
|
17
32
|
exports.Customer = Customer;
|
|
18
33
|
tslib_1.__decorate([
|
|
@@ -39,9 +54,42 @@ tslib_1.__decorate([
|
|
|
39
54
|
(0, graphql_1.Field)({ description: 'Customer display name.' }),
|
|
40
55
|
tslib_1.__metadata("design:type", String)
|
|
41
56
|
], Customer.prototype, "displayName", void 0);
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, graphql_1.Field)(() => Gender, {
|
|
59
|
+
nullable: true,
|
|
60
|
+
description: 'Customer gender (facts.gender metafield).',
|
|
61
|
+
}),
|
|
62
|
+
tslib_1.__metadata("design:type", String)
|
|
63
|
+
], Customer.prototype, "gender", void 0);
|
|
64
|
+
tslib_1.__decorate([
|
|
65
|
+
(0, graphql_1.Field)({
|
|
66
|
+
nullable: true,
|
|
67
|
+
description: 'Customer date of birth as an ISO date string, YYYY-MM-DD (facts.birth_date metafield).',
|
|
68
|
+
}),
|
|
69
|
+
tslib_1.__metadata("design:type", String)
|
|
70
|
+
], Customer.prototype, "birthDate", void 0);
|
|
42
71
|
exports.Customer = Customer = tslib_1.__decorate([
|
|
43
72
|
(0, graphql_1.ObjectType)({ description: 'A Shopify customer.' })
|
|
44
73
|
], Customer);
|
|
74
|
+
let CustomerUpdateInput = class CustomerUpdateInput {
|
|
75
|
+
gender;
|
|
76
|
+
birthDate;
|
|
77
|
+
};
|
|
78
|
+
exports.CustomerUpdateInput = CustomerUpdateInput;
|
|
79
|
+
tslib_1.__decorate([
|
|
80
|
+
(0, graphql_1.Field)(() => Gender, { nullable: true, description: 'Customer gender.' }),
|
|
81
|
+
tslib_1.__metadata("design:type", String)
|
|
82
|
+
], CustomerUpdateInput.prototype, "gender", void 0);
|
|
83
|
+
tslib_1.__decorate([
|
|
84
|
+
(0, graphql_1.Field)({
|
|
85
|
+
nullable: true,
|
|
86
|
+
description: 'Customer date of birth as an ISO date string (YYYY-MM-DD).',
|
|
87
|
+
}),
|
|
88
|
+
tslib_1.__metadata("design:type", String)
|
|
89
|
+
], CustomerUpdateInput.prototype, "birthDate", void 0);
|
|
90
|
+
exports.CustomerUpdateInput = CustomerUpdateInput = tslib_1.__decorate([
|
|
91
|
+
(0, graphql_1.InputType)({ description: 'Fields to update on a customer profile.' })
|
|
92
|
+
], CustomerUpdateInput);
|
|
45
93
|
let CustomerLoginResult = class CustomerLoginResult {
|
|
46
94
|
customerAccessToken;
|
|
47
95
|
expiresAt;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customer.types.js","sourceRoot":"","sources":["../../src/customer/customer.types.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"customer.types.js","sourceRoot":"","sources":["../../src/customer/customer.types.ts"],"names":[],"mappings":"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"}
|