medusa-product-helper 0.0.1 → 0.0.3

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.
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = void 0;
4
+ const wishlist_1 = require("../../../../modules/wishlist");
5
+ const GET = async (req, res) => {
6
+ try {
7
+ const wishlistService = req.scope.resolve(wishlist_1.WISHLIST_MODULE);
8
+ const productId = req.query.product_id;
9
+ // If product_id is provided, return count for that product only
10
+ if (productId) {
11
+ const counts = await wishlistService.getWishlistCounts([productId]);
12
+ const count = counts.find((c) => c.product_id === productId);
13
+ res.json({
14
+ product_id: productId,
15
+ wishlist_count: count?.wishlist_count || 0,
16
+ });
17
+ return;
18
+ }
19
+ // Otherwise, return counts for all products
20
+ const counts = await wishlistService.getWishlistCounts();
21
+ res.json({ stats: counts });
22
+ }
23
+ catch (error) {
24
+ if (error instanceof Error) {
25
+ res.status(400).json({ message: error.message });
26
+ return;
27
+ }
28
+ res.status(500).json({ message: "Internal server error" });
29
+ }
30
+ };
31
+ exports.GET = GET;
32
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3dpc2hsaXN0L3N0YXRzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLDJEQUE4RDtBQUd2RCxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQ3RCLEdBQWtCLEVBQ2xCLEdBQW1CLEVBQ0osRUFBRTtJQUNqQixJQUFJLENBQUM7UUFDSCxNQUFNLGVBQWUsR0FBMEIsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQzlELDBCQUFlLENBQ2hCLENBQUE7UUFFRCxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLFVBQWdDLENBQUE7UUFFNUQsZ0VBQWdFO1FBQ2hFLElBQUksU0FBUyxFQUFFLENBQUM7WUFDZCxNQUFNLE1BQU0sR0FBRyxNQUFNLGVBQWUsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUE7WUFDbkUsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsS0FBSyxTQUFTLENBQUMsQ0FBQTtZQUU1RCxHQUFHLENBQUMsSUFBSSxDQUFDO2dCQUNQLFVBQVUsRUFBRSxTQUFTO2dCQUNyQixjQUFjLEVBQUUsS0FBSyxFQUFFLGNBQWMsSUFBSSxDQUFDO2FBQzNDLENBQUMsQ0FBQTtZQUNGLE9BQU07UUFDUixDQUFDO1FBRUQsNENBQTRDO1FBQzVDLE1BQU0sTUFBTSxHQUFHLE1BQU0sZUFBZSxDQUFDLGlCQUFpQixFQUFFLENBQUE7UUFFeEQsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFBO0lBQzdCLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsSUFBSSxLQUFLLFlBQVksS0FBSyxFQUFFLENBQUM7WUFDM0IsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUE7WUFDaEQsT0FBTTtRQUNSLENBQUM7UUFDRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxDQUFDLENBQUE7SUFDNUQsQ0FBQztBQUNILENBQUMsQ0FBQTtBQWxDWSxRQUFBLEdBQUcsT0FrQ2YifQ==
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DELETE = void 0;
4
+ const remove_from_wishlist_1 = require("../../../../workflows/remove-from-wishlist");
5
+ const DELETE = async (req, res) => {
6
+ try {
7
+ const { product_id } = req.params;
8
+ if (!product_id) {
9
+ res.status(400).json({ message: "product_id is required" });
10
+ return;
11
+ }
12
+ // Get customer ID from auth context
13
+ const customerId = req.auth_context?.actor_id;
14
+ if (!customerId) {
15
+ res.status(401).json({ message: "Unauthorized" });
16
+ return;
17
+ }
18
+ // Execute remove from wishlist workflow
19
+ const { result } = await (0, remove_from_wishlist_1.removeFromWishlistWorkflow)(req.scope).run({
20
+ input: {
21
+ customer_id: customerId,
22
+ product_id: product_id,
23
+ },
24
+ });
25
+ res.json({ success: result.success });
26
+ }
27
+ catch (error) {
28
+ if (error instanceof Error) {
29
+ res.status(400).json({ message: error.message });
30
+ return;
31
+ }
32
+ res.status(500).json({ message: "Internal server error" });
33
+ }
34
+ };
35
+ exports.DELETE = DELETE;
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3dpc2hsaXN0L1twcm9kdWN0X2lkXS9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSxxRkFBdUY7QUFFaEYsTUFBTSxNQUFNLEdBQUcsS0FBSyxFQUN6QixHQUFrQixFQUNsQixHQUFtQixFQUNKLEVBQUU7SUFDakIsSUFBSSxDQUFDO1FBQ0gsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUE7UUFFakMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2hCLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLENBQUMsQ0FBQTtZQUMzRCxPQUFNO1FBQ1IsQ0FBQztRQUVELG9DQUFvQztRQUNwQyxNQUFNLFVBQVUsR0FBSSxHQUFXLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQTtRQUV0RCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDaEIsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQTtZQUNqRCxPQUFNO1FBQ1IsQ0FBQztRQUVELHdDQUF3QztRQUN4QyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLGlEQUEwQixFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDakUsS0FBSyxFQUFFO2dCQUNMLFdBQVcsRUFBRSxVQUFVO2dCQUN2QixVQUFVLEVBQUUsVUFBVTthQUN2QjtTQUNGLENBQUMsQ0FBQTtRQUVGLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUE7SUFDdkMsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixJQUFJLEtBQUssWUFBWSxLQUFLLEVBQUUsQ0FBQztZQUMzQixHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQTtZQUNoRCxPQUFNO1FBQ1IsQ0FBQztRQUNELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLENBQUMsQ0FBQTtJQUM1RCxDQUFDO0FBQ0gsQ0FBQyxDQUFBO0FBcENZLFFBQUEsTUFBTSxVQW9DbEIifQ==
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = exports.POST = void 0;
4
+ const add_to_wishlist_1 = require("../../../workflows/add-to-wishlist");
5
+ const get_wishlist_1 = require("../../../workflows/get-wishlist");
6
+ const validators_1 = require("./validators");
7
+ const POST = async (req, res) => {
8
+ try {
9
+ // Validate request body
10
+ const validated = validators_1.AddToWishlistSchema.parse(req.body);
11
+ // Get customer ID from auth context
12
+ const customerId = req.auth_context?.actor_id;
13
+ if (!customerId) {
14
+ res.status(401).json({ message: "Unauthorized" });
15
+ return;
16
+ }
17
+ // Execute add to wishlist workflow
18
+ const { result } = await (0, add_to_wishlist_1.addToWishlistWorkflow)(req.scope).run({
19
+ input: {
20
+ customer_id: customerId,
21
+ product_id: validated.product_id,
22
+ },
23
+ });
24
+ res.json({ wishlist_item: result.wishlist_item });
25
+ }
26
+ catch (error) {
27
+ if (error instanceof Error) {
28
+ res.status(400).json({ message: error.message });
29
+ return;
30
+ }
31
+ res.status(500).json({ message: "Internal server error" });
32
+ }
33
+ };
34
+ exports.POST = POST;
35
+ const GET = async (req, res) => {
36
+ try {
37
+ // Get customer ID from auth context
38
+ const customerId = req.auth_context?.actor_id;
39
+ if (!customerId) {
40
+ res.status(401).json({ message: "Unauthorized" });
41
+ return;
42
+ }
43
+ // Parse query parameters
44
+ const includeDetails = req.query.include_details === "true" ||
45
+ req.query.include_details === "1";
46
+ // Execute get wishlist workflow
47
+ const { result } = await (0, get_wishlist_1.getWishlistWorkflow)(req.scope).run({
48
+ input: {
49
+ customer_id: customerId,
50
+ options: {
51
+ includeDetails: includeDetails,
52
+ },
53
+ },
54
+ });
55
+ res.json({ wishlist: result.wishlist });
56
+ }
57
+ catch (error) {
58
+ if (error instanceof Error) {
59
+ res.status(400).json({ message: error.message });
60
+ return;
61
+ }
62
+ res.status(500).json({ message: "Internal server error" });
63
+ }
64
+ };
65
+ exports.GET = GET;
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3dpc2hsaXN0L3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHdFQUEwRTtBQUMxRSxrRUFBcUU7QUFDckUsNkNBQWtEO0FBRTNDLE1BQU0sSUFBSSxHQUFHLEtBQUssRUFDdkIsR0FBa0IsRUFDbEIsR0FBbUIsRUFDSixFQUFFO0lBQ2pCLElBQUksQ0FBQztRQUNILHdCQUF3QjtRQUN4QixNQUFNLFNBQVMsR0FBRyxnQ0FBbUIsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFBO1FBRXJELG9DQUFvQztRQUNwQyxNQUFNLFVBQVUsR0FBSSxHQUFXLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQTtRQUV0RCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDaEIsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQTtZQUNqRCxPQUFNO1FBQ1IsQ0FBQztRQUVELG1DQUFtQztRQUNuQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLHVDQUFxQixFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDNUQsS0FBSyxFQUFFO2dCQUNMLFdBQVcsRUFBRSxVQUFVO2dCQUN2QixVQUFVLEVBQUUsU0FBUyxDQUFDLFVBQVU7YUFDakM7U0FDRixDQUFDLENBQUE7UUFFRixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsYUFBYSxFQUFFLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFBO0lBQ25ELENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsSUFBSSxLQUFLLFlBQVksS0FBSyxFQUFFLENBQUM7WUFDM0IsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUE7WUFDaEQsT0FBTTtRQUNSLENBQUM7UUFDRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxDQUFDLENBQUE7SUFDNUQsQ0FBQztBQUNILENBQUMsQ0FBQTtBQWhDWSxRQUFBLElBQUksUUFnQ2hCO0FBRU0sTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUN0QixHQUFrQixFQUNsQixHQUFtQixFQUNKLEVBQUU7SUFDakIsSUFBSSxDQUFDO1FBQ0gsb0NBQW9DO1FBQ3BDLE1BQU0sVUFBVSxHQUFJLEdBQVcsQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFBO1FBRXRELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNoQixHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFBO1lBQ2pELE9BQU07UUFDUixDQUFDO1FBRUQseUJBQXlCO1FBQ3pCLE1BQU0sY0FBYyxHQUNsQixHQUFHLENBQUMsS0FBSyxDQUFDLGVBQWUsS0FBSyxNQUFNO1lBQ3BDLEdBQUcsQ0FBQyxLQUFLLENBQUMsZUFBZSxLQUFLLEdBQUcsQ0FBQTtRQUVuQyxnQ0FBZ0M7UUFDaEMsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sSUFBQSxrQ0FBbUIsRUFBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQzFELEtBQUssRUFBRTtnQkFDTCxXQUFXLEVBQUUsVUFBVTtnQkFDdkIsT0FBTyxFQUFFO29CQUNQLGNBQWMsRUFBRSxjQUFjO2lCQUMvQjthQUNGO1NBQ0YsQ0FBQyxDQUFBO1FBRUYsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtJQUN6QyxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLElBQUksS0FBSyxZQUFZLEtBQUssRUFBRSxDQUFDO1lBQzNCLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFBO1lBQ2hELE9BQU07UUFDUixDQUFDO1FBQ0QsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsQ0FBQyxDQUFBO0lBQzVELENBQUM7QUFDSCxDQUFDLENBQUE7QUFwQ1ksUUFBQSxHQUFHLE9Bb0NmIn0=
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AddToWishlistSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.AddToWishlistSchema = zod_1.z.object({
6
+ product_id: zod_1.z.string().min(1, "product_id is required"),
7
+ });
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvc3RvcmUvd2lzaGxpc3QvdmFsaWRhdG9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2QkFBdUI7QUFFVixRQUFBLG1CQUFtQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDMUMsVUFBVSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLHdCQUF3QixDQUFDO0NBQ3hELENBQUMsQ0FBQSJ9
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WishlistModuleService = exports.WISHLIST_MODULE = void 0;
7
+ const utils_1 = require("@medusajs/framework/utils");
8
+ const service_1 = __importDefault(require("./service"));
9
+ exports.WishlistModuleService = service_1.default;
10
+ exports.WISHLIST_MODULE = "wishlist";
11
+ exports.default = (0, utils_1.Module)(exports.WISHLIST_MODULE, {
12
+ service: service_1.default,
13
+ });
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy93aXNobGlzdC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxxREFBa0Q7QUFDbEQsd0RBQTZDO0FBUXBDLGdDQVJGLGlCQUFxQixDQVFFO0FBTmpCLFFBQUEsZUFBZSxHQUFHLFVBQVUsQ0FBQTtBQUV6QyxrQkFBZSxJQUFBLGNBQU0sRUFBQyx1QkFBZSxFQUFFO0lBQ3JDLE9BQU8sRUFBRSxpQkFBcUI7Q0FDL0IsQ0FBQyxDQUFBIn0=
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Migration20251125060140 = void 0;
4
+ const migrations_1 = require("@mikro-orm/migrations");
5
+ class Migration20251125060140 extends migrations_1.Migration {
6
+ async up() {
7
+ this.addSql(`create table if not exists "wishlist" ("id" text not null, "customer_id" text not null, "product_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "wishlist_pkey" primary key ("id"));`);
8
+ this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_wishlist_deleted_at" ON "wishlist" (deleted_at) WHERE deleted_at IS NULL;`);
9
+ }
10
+ async down() {
11
+ this.addSql(`drop table if exists "wishlist" cascade;`);
12
+ }
13
+ }
14
+ exports.Migration20251125060140 = Migration20251125060140;
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uMjAyNTExMjUwNjAxNDAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy93aXNobGlzdC9taWdyYXRpb25zL01pZ3JhdGlvbjIwMjUxMTI1MDYwMTQwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHNEQUFrRDtBQUVsRCxNQUFhLHVCQUF3QixTQUFRLHNCQUFTO0lBRTNDLEtBQUssQ0FBQyxFQUFFO1FBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxzU0FBc1MsQ0FBQyxDQUFDO1FBQ3BULElBQUksQ0FBQyxNQUFNLENBQUMsMkdBQTJHLENBQUMsQ0FBQztJQUMzSCxDQUFDO0lBRVEsS0FBSyxDQUFDLElBQUk7UUFDakIsSUFBSSxDQUFDLE1BQU0sQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO0lBQzFELENBQUM7Q0FFRjtBQVhELDBEQVdDIn0=
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Wishlist = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ exports.Wishlist = utils_1.model.define("wishlist", {
6
+ id: utils_1.model.id().primaryKey(),
7
+ customer_id: utils_1.model.text().searchable(),
8
+ product_id: utils_1.model.text().searchable(),
9
+ });
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2lzaGxpc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy93aXNobGlzdC9tb2RlbHMvd2lzaGxpc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscURBQWlEO0FBRXBDLFFBQUEsUUFBUSxHQUFHLGFBQUssQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO0lBQy9DLEVBQUUsRUFBRSxhQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsVUFBVSxFQUFFO0lBQzNCLFdBQVcsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsVUFBVSxFQUFFO0lBQ3RDLFVBQVUsRUFBRSxhQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsVUFBVSxFQUFFO0NBQ3RDLENBQUMsQ0FBQSJ9
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@medusajs/framework/utils");
4
+ const wishlist_1 = require("./models/wishlist");
5
+ class WishlistModuleService extends (0, utils_1.MedusaService)({
6
+ Wishlist: wishlist_1.Wishlist,
7
+ }) {
8
+ /**
9
+ * Add a product to customer's wishlist (idempotent - no duplicates)
10
+ */
11
+ async addToWishlist(customerId, productId) {
12
+ // Check if already exists
13
+ const existing = await this.listWishlists({
14
+ customer_id: customerId,
15
+ product_id: productId,
16
+ });
17
+ if (existing.length > 0) {
18
+ return existing[0];
19
+ }
20
+ // Create new wishlist entry
21
+ const wishlist = await this.createWishlists({
22
+ customer_id: customerId,
23
+ product_id: productId,
24
+ });
25
+ return wishlist;
26
+ }
27
+ /**
28
+ * Remove a product from customer's wishlist
29
+ */
30
+ async removeFromWishlist(customerId, productId) {
31
+ const wishlistItems = await this.listWishlists({
32
+ customer_id: customerId,
33
+ product_id: productId,
34
+ });
35
+ if (wishlistItems.length > 0) {
36
+ await this.deleteWishlists(wishlistItems.map((item) => item.id));
37
+ }
38
+ }
39
+ /**
40
+ * Get customer's wishlist with optional filtering and details
41
+ */
42
+ async getWishlist(customerId, options = {}) {
43
+ const filters = {
44
+ customer_id: customerId,
45
+ };
46
+ if (options.productIds && options.productIds.length > 0) {
47
+ filters.product_id = options.productIds;
48
+ }
49
+ const wishlistItems = await this.listWishlists(filters);
50
+ if (options.includeDetails) {
51
+ return wishlistItems;
52
+ }
53
+ // Return only product IDs
54
+ return wishlistItems.map((item) => item.product_id);
55
+ }
56
+ /**
57
+ * Get wishlist counts per product (for admin)
58
+ */
59
+ async getWishlistCounts(productIds) {
60
+ const filters = {};
61
+ if (productIds && productIds.length > 0) {
62
+ filters.product_id = productIds;
63
+ }
64
+ const wishlistItems = await this.listWishlists(filters);
65
+ // Count occurrences per product_id
66
+ const counts = new Map();
67
+ for (const item of wishlistItems) {
68
+ const productId = item.product_id;
69
+ counts.set(productId, (counts.get(productId) || 0) + 1);
70
+ }
71
+ return Array.from(counts.entries()).map(([product_id, wishlist_count]) => ({
72
+ product_id,
73
+ wishlist_count,
74
+ }));
75
+ }
76
+ /**
77
+ * Check if a product is in customer's wishlist
78
+ */
79
+ async isInWishlist(customerId, productId) {
80
+ const wishlistItems = await this.listWishlists({
81
+ customer_id: customerId,
82
+ product_id: productId,
83
+ });
84
+ return wishlistItems.length > 0;
85
+ }
86
+ }
87
+ exports.default = WishlistModuleService;
88
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3dpc2hsaXN0L3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxxREFBeUQ7QUFDekQsZ0RBQTRDO0FBb0I1QyxNQUFNLHFCQUFzQixTQUFRLElBQUEscUJBQWEsRUFBQztJQUNoRCxRQUFRLEVBQVIsbUJBQVE7Q0FDVCxDQUFDO0lBQ0E7O09BRUc7SUFDSCxLQUFLLENBQUMsYUFBYSxDQUNqQixVQUFrQixFQUNsQixTQUFpQjtRQUVqQiwwQkFBMEI7UUFDMUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQ3hDLFdBQVcsRUFBRSxVQUFVO1lBQ3ZCLFVBQVUsRUFBRSxTQUFTO1NBQ3RCLENBQUMsQ0FBQTtRQUVGLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QixPQUFPLFFBQVEsQ0FBQyxDQUFDLENBQWlCLENBQUE7UUFDcEMsQ0FBQztRQUVELDRCQUE0QjtRQUM1QixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUM7WUFDMUMsV0FBVyxFQUFFLFVBQVU7WUFDdkIsVUFBVSxFQUFFLFNBQVM7U0FDdEIsQ0FBQyxDQUFBO1FBRUYsT0FBTyxRQUF3QixDQUFBO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxrQkFBa0IsQ0FDdEIsVUFBa0IsRUFDbEIsU0FBaUI7UUFFakIsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQzdDLFdBQVcsRUFBRSxVQUFVO1lBQ3ZCLFVBQVUsRUFBRSxTQUFTO1NBQ3RCLENBQUMsQ0FBQTtRQUVGLElBQUksYUFBYSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUE7UUFDbEUsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxXQUFXLENBQ2YsVUFBa0IsRUFDbEIsVUFBOEIsRUFBRTtRQUVoQyxNQUFNLE9BQU8sR0FBNEI7WUFDdkMsV0FBVyxFQUFFLFVBQVU7U0FDeEIsQ0FBQTtRQUVELElBQUksT0FBTyxDQUFDLFVBQVUsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4RCxPQUFPLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUE7UUFDekMsQ0FBQztRQUVELE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUV2RCxJQUFJLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUMzQixPQUFPLGFBQStCLENBQUE7UUFDeEMsQ0FBQztRQUVELDBCQUEwQjtRQUMxQixPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUNyRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsaUJBQWlCLENBQ3JCLFVBQXFCO1FBRXJCLE1BQU0sT0FBTyxHQUE0QixFQUFFLENBQUE7UUFFM0MsSUFBSSxVQUFVLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QyxPQUFPLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQTtRQUNqQyxDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBRXZELG1DQUFtQztRQUNuQyxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQTtRQUV4QyxLQUFLLE1BQU0sSUFBSSxJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFvQixDQUFBO1lBQzNDLE1BQU0sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTtRQUN6RCxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsVUFBVSxFQUFFLGNBQWMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3pFLFVBQVU7WUFDVixjQUFjO1NBQ2YsQ0FBQyxDQUFDLENBQUE7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUNoQixVQUFrQixFQUNsQixTQUFpQjtRQUVqQixNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUM7WUFDN0MsV0FBVyxFQUFFLFVBQVU7WUFDdkIsVUFBVSxFQUFFLFNBQVM7U0FDdEIsQ0FBQyxDQUFBO1FBRUYsT0FBTyxhQUFhLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQTtJQUNqQyxDQUFDO0NBQ0Y7QUFFRCxrQkFBZSxxQkFBcUIsQ0FBQSJ9
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWishlist = getWishlist;
4
+ const wishlist_1 = require("../../modules/wishlist");
5
+ /**
6
+ * Helper function to get customer's wishlist
7
+ * This function can be used directly by UI components without implementing the entire logic
8
+ *
9
+ * @param container - Medusa container instance
10
+ * @param customerId - Customer ID
11
+ * @param options - Options for getting wishlist
12
+ * @returns Promise of wishlist items (IDs or full details based on options)
13
+ *
14
+ * @example
15
+ * // Get only product IDs
16
+ * const wishlist = await getWishlist(container, customerId)
17
+ * // Returns: ['prod_123', 'prod_456']
18
+ *
19
+ * @example
20
+ * // Get full product details
21
+ * const wishlist = await getWishlist(container, customerId, { includeDetails: true })
22
+ * // Returns: [{ product_id: 'prod_123', product: {...}, ... }]
23
+ */
24
+ async function getWishlist(container, customerId, options = {}) {
25
+ const wishlistService = container.resolve(wishlist_1.WISHLIST_MODULE);
26
+ const serviceOptions = {
27
+ includeDetails: options.includeDetails ?? false,
28
+ productIds: options.productIds,
29
+ };
30
+ const wishlist = await wishlistService.getWishlist(customerId, serviceOptions);
31
+ // If includeDetails is false, wishlist is an array of product IDs
32
+ if (!options.includeDetails) {
33
+ return wishlist;
34
+ }
35
+ // If includeDetails is true, we need to enrich with product details
36
+ // For now, return the wishlist items as-is (they should already have details if includeDetails was true)
37
+ // In a real implementation, you might want to use remote query to enrich here
38
+ return wishlist;
39
+ }
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3NoYXJlZC93aXNobGlzdC9oZWxwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE4Q0Esa0NBeUJDO0FBdEVELHFEQUF3RDtBQTBCeEQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNJLEtBQUssVUFBVSxXQUFXLENBQy9CLFNBQXdCLEVBQ3hCLFVBQWtCLEVBQ2xCLFVBQW9DLEVBQUU7SUFFdEMsTUFBTSxlQUFlLEdBQTBCLFNBQVMsQ0FBQyxPQUFPLENBQzlELDBCQUFlLENBQ2hCLENBQUE7SUFFRCxNQUFNLGNBQWMsR0FBdUI7UUFDekMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjLElBQUksS0FBSztRQUMvQyxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7S0FDL0IsQ0FBQTtJQUVELE1BQU0sUUFBUSxHQUFHLE1BQU0sZUFBZSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsY0FBYyxDQUFDLENBQUE7SUFFOUUsa0VBQWtFO0lBQ2xFLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDNUIsT0FBTyxRQUFvQixDQUFBO0lBQzdCLENBQUM7SUFFRCxvRUFBb0U7SUFDcEUseUdBQXlHO0lBQ3pHLDhFQUE4RTtJQUM5RSxPQUFPLFFBQWtDLENBQUE7QUFDM0MsQ0FBQyJ9
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWishlist = void 0;
4
+ var helper_1 = require("./helper");
5
+ Object.defineProperty(exports, "getWishlist", { enumerable: true, get: function () { return helper_1.getWishlist; } });
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvc2hhcmVkL3dpc2hsaXN0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUFzQztBQUE3QixxR0FBQSxXQUFXLE9BQUEifQ==
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addToWishlistWorkflow = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const wishlist_1 = require("../modules/wishlist");
6
+ const validateCustomerAndProductStep = (0, workflows_sdk_1.createStep)("validate-customer-and-product", async (input, { container }) => {
7
+ // Validate customer exists using remote query
8
+ const remoteQuery = container.resolve("remoteQuery");
9
+ const customerQuery = {
10
+ customer: {
11
+ fields: ["id"],
12
+ filters: {
13
+ id: input.customer_id,
14
+ },
15
+ },
16
+ };
17
+ const [customer] = await remoteQuery(customerQuery);
18
+ if (!customer) {
19
+ throw new Error(`Customer with id ${input.customer_id} not found`);
20
+ }
21
+ // Validate product exists using remote query
22
+ const productQuery = {
23
+ product: {
24
+ fields: ["id"],
25
+ filters: {
26
+ id: input.product_id,
27
+ },
28
+ },
29
+ };
30
+ const [product] = await remoteQuery(productQuery);
31
+ if (!product) {
32
+ throw new Error(`Product with id ${input.product_id} not found`);
33
+ }
34
+ return new workflows_sdk_1.StepResponse({
35
+ customer_id: input.customer_id,
36
+ product_id: input.product_id,
37
+ });
38
+ });
39
+ const addToWishlistStep = (0, workflows_sdk_1.createStep)("add-to-wishlist", async (input, { container }) => {
40
+ const wishlistService = container.resolve(wishlist_1.WISHLIST_MODULE);
41
+ const wishlistItem = await wishlistService.addToWishlist(input.customer_id, input.product_id);
42
+ return new workflows_sdk_1.StepResponse(wishlistItem);
43
+ });
44
+ exports.addToWishlistWorkflow = (0, workflows_sdk_1.createWorkflow)("add-to-wishlist", (input) => {
45
+ const validated = validateCustomerAndProductStep(input);
46
+ const wishlistItem = addToWishlistStep(validated);
47
+ return new workflows_sdk_1.WorkflowResponse({
48
+ wishlist_item: wishlistItem,
49
+ });
50
+ });
51
+ exports.default = exports.addToWishlistWorkflow;
52
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkLXRvLXdpc2hsaXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9hZGQtdG8td2lzaGxpc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBSzBDO0FBQzFDLGtEQUFxRDtBQWtCckQsTUFBTSw4QkFBOEIsR0FBRyxJQUFBLDBCQUFVLEVBQy9DLCtCQUErQixFQUMvQixLQUFLLEVBQUUsS0FBeUIsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7SUFDakQsOENBQThDO0lBQzlDLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQ25DLGFBQWEsQ0FDb0IsQ0FBQTtJQUVuQyxNQUFNLGFBQWEsR0FBRztRQUNwQixRQUFRLEVBQUU7WUFDUixNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUM7WUFDZCxPQUFPLEVBQUU7Z0JBQ1AsRUFBRSxFQUFFLEtBQUssQ0FBQyxXQUFXO2FBQ3RCO1NBQ0Y7S0FDRixDQUFBO0lBRUQsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sV0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBRW5ELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLEtBQUssQ0FBQyxXQUFXLFlBQVksQ0FBQyxDQUFBO0lBQ3BFLENBQUM7SUFFRCw2Q0FBNkM7SUFDN0MsTUFBTSxZQUFZLEdBQUc7UUFDbkIsT0FBTyxFQUFFO1lBQ1AsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDO1lBQ2QsT0FBTyxFQUFFO2dCQUNQLEVBQUUsRUFBRSxLQUFLLENBQUMsVUFBVTthQUNyQjtTQUNGO0tBQ0YsQ0FBQTtJQUVELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxNQUFNLFdBQVcsQ0FBQyxZQUFZLENBQUMsQ0FBQTtJQUVqRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixLQUFLLENBQUMsVUFBVSxZQUFZLENBQUMsQ0FBQTtJQUNsRSxDQUFDO0lBRUQsT0FBTyxJQUFJLDRCQUFZLENBQUM7UUFDdEIsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO1FBQzlCLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtLQUM3QixDQUFDLENBQUE7QUFDSixDQUFDLENBQ0YsQ0FBQTtBQUVELE1BQU0saUJBQWlCLEdBQUcsSUFBQSwwQkFBVSxFQUNsQyxpQkFBaUIsRUFDakIsS0FBSyxFQUNILEtBQWtELEVBQ2xELEVBQUUsU0FBUyxFQUFFLEVBQ2IsRUFBRTtJQUNGLE1BQU0sZUFBZSxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUM5RCwwQkFBZSxDQUNoQixDQUFBO0lBRUQsTUFBTSxZQUFZLEdBQUcsTUFBTSxlQUFlLENBQUMsYUFBYSxDQUN0RCxLQUFLLENBQUMsV0FBVyxFQUNqQixLQUFLLENBQUMsVUFBVSxDQUNqQixDQUFBO0lBRUQsT0FBTyxJQUFJLDRCQUFZLENBQUMsWUFBWSxDQUFDLENBQUE7QUFDdkMsQ0FBQyxDQUNGLENBQUE7QUFFWSxRQUFBLHFCQUFxQixHQUFHLElBQUEsOEJBQWMsRUFDakQsaUJBQWlCLEVBQ2pCLENBQUMsS0FBeUIsRUFBeUMsRUFBRTtJQUNuRSxNQUFNLFNBQVMsR0FBRyw4QkFBOEIsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUN2RCxNQUFNLFlBQVksR0FBRyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsQ0FBQTtJQUVqRCxPQUFPLElBQUksZ0NBQWdCLENBQUM7UUFDMUIsYUFBYSxFQUFFLFlBQVk7S0FDNUIsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUNGLENBQUE7QUFFRCxrQkFBZSw2QkFBcUIsQ0FBQSJ9
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWishlistWorkflow = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const utils_1 = require("@medusajs/framework/utils");
6
+ const wishlist_1 = require("../modules/wishlist");
7
+ const fetchWishlistItemsStep = (0, workflows_sdk_1.createStep)("fetch-wishlist-items", async (input, { container }) => {
8
+ const wishlistService = container.resolve(wishlist_1.WISHLIST_MODULE);
9
+ const wishlist = await wishlistService.getWishlist(input.customer_id, input.options);
10
+ const includeDetails = input.options?.includeDetails ?? false;
11
+ // Convert to consistent format
12
+ let formattedWishlist;
13
+ if (includeDetails) {
14
+ formattedWishlist = wishlist.map((item) => ({
15
+ id: item.id,
16
+ product_id: item.product_id,
17
+ created_at: item.created_at,
18
+ }));
19
+ }
20
+ else {
21
+ formattedWishlist = wishlist.map((product_id) => ({
22
+ product_id,
23
+ }));
24
+ }
25
+ return new workflows_sdk_1.StepResponse({
26
+ wishlist: formattedWishlist,
27
+ includeDetails,
28
+ });
29
+ });
30
+ const enrichWithProductDetailsStep = (0, workflows_sdk_1.createStep)("enrich-with-product-details", async (input, { container }) => {
31
+ if (!input.includeDetails || input.wishlist.length === 0) {
32
+ // Return as-is if no details needed or empty
33
+ return new workflows_sdk_1.StepResponse({ wishlist: input.wishlist });
34
+ }
35
+ // Get full wishlist items with product_id
36
+ const wishlistItems = input.wishlist;
37
+ const productIds = wishlistItems.map((item) => item.product_id);
38
+ // Fetch product details using remote query
39
+ const remoteQuery = container.resolve(utils_1.ContainerRegistrationKeys.REMOTE_QUERY);
40
+ const queryObject = (0, utils_1.remoteQueryObjectFromString)({
41
+ entryPoint: "product",
42
+ fields: [
43
+ "id",
44
+ "title",
45
+ "handle",
46
+ "description",
47
+ "thumbnail",
48
+ "status",
49
+ "created_at",
50
+ "updated_at",
51
+ ],
52
+ variables: {
53
+ filters: {
54
+ id: productIds,
55
+ },
56
+ },
57
+ });
58
+ const products = await remoteQuery(queryObject);
59
+ // Create a map of product_id to product details
60
+ const productMap = new Map(products.map((product) => [product.id, product]));
61
+ // Merge wishlist items with product details
62
+ const enrichedWishlist = wishlistItems.map((item) => ({
63
+ id: item.id,
64
+ product_id: item.product_id,
65
+ product: productMap.get(item.product_id) || null,
66
+ created_at: item.created_at,
67
+ }));
68
+ return new workflows_sdk_1.StepResponse({ wishlist: enrichedWishlist });
69
+ });
70
+ exports.getWishlistWorkflow = (0, workflows_sdk_1.createWorkflow)("get-wishlist", (input) => {
71
+ const wishlistData = fetchWishlistItemsStep(input);
72
+ const enrichedWishlist = enrichWithProductDetailsStep(wishlistData);
73
+ return new workflows_sdk_1.WorkflowResponse({
74
+ wishlist: enrichedWishlist.wishlist,
75
+ });
76
+ });
77
+ exports.default = exports.getWishlistWorkflow;
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LXdpc2hsaXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9nZXQtd2lzaGxpc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBSzBDO0FBQzFDLHFEQUdrQztBQUVsQyxrREFBcUQ7QUFvQnJELE1BQU0sc0JBQXNCLEdBQUcsSUFBQSwwQkFBVSxFQUN2QyxzQkFBc0IsRUFDdEIsS0FBSyxFQUFFLEtBQXVCLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO0lBQy9DLE1BQU0sZUFBZSxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUM5RCwwQkFBZSxDQUNoQixDQUFBO0lBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxlQUFlLENBQUMsV0FBVyxDQUNoRCxLQUFLLENBQUMsV0FBVyxFQUNqQixLQUFLLENBQUMsT0FBTyxDQUNkLENBQUE7SUFFRCxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLGNBQWMsSUFBSSxLQUFLLENBQUE7SUFFN0QsK0JBQStCO0lBQy9CLElBQUksaUJBS0YsQ0FBQTtJQUVGLElBQUksY0FBYyxFQUFFLENBQUM7UUFDbkIsaUJBQWlCLEdBQUksUUFLbEIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDakIsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1lBQ1gsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzNCLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtTQUM1QixDQUFDLENBQUMsQ0FBQTtJQUNMLENBQUM7U0FBTSxDQUFDO1FBQ04saUJBQWlCLEdBQUksUUFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDOUQsVUFBVTtTQUNYLENBQUMsQ0FBQyxDQUFBO0lBQ0wsQ0FBQztJQUVELE9BQU8sSUFBSSw0QkFBWSxDQUFDO1FBQ3RCLFFBQVEsRUFBRSxpQkFBaUI7UUFDM0IsY0FBYztLQUNmLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FDRixDQUFBO0FBRUQsTUFBTSw0QkFBNEIsR0FBRyxJQUFBLDBCQUFVLEVBQzdDLDZCQUE2QixFQUM3QixLQUFLLEVBQ0gsS0FHQyxFQUNELEVBQUUsU0FBUyxFQUFFLEVBQ2IsRUFBRTtJQUNGLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3pELDZDQUE2QztRQUM3QyxPQUFPLElBQUksNEJBQVksQ0FBQyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtJQUN2RCxDQUFDO0lBRUQsMENBQTBDO0lBQzFDLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxRQUsxQixDQUFBO0lBRUYsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQW9CLENBQUMsQ0FBQTtJQUV6RSwyQ0FBMkM7SUFDM0MsTUFBTSxXQUFXLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FDbkMsaUNBQXlCLENBQUMsWUFBWSxDQUN2QyxDQUFBO0lBRUQsTUFBTSxXQUFXLEdBQUcsSUFBQSxtQ0FBMkIsRUFBQztRQUM5QyxVQUFVLEVBQUUsU0FBUztRQUNyQixNQUFNLEVBQUU7WUFDTixJQUFJO1lBQ0osT0FBTztZQUNQLFFBQVE7WUFDUixhQUFhO1lBQ2IsV0FBVztZQUNYLFFBQVE7WUFDUixZQUFZO1lBQ1osWUFBWTtTQUNiO1FBQ0QsU0FBUyxFQUFFO1lBQ1QsT0FBTyxFQUFFO2dCQUNQLEVBQUUsRUFBRSxVQUFVO2FBQ2Y7U0FDRjtLQUNGLENBQUMsQ0FBQTtJQUVGLE1BQU0sUUFBUSxHQUFHLE1BQU0sV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFBO0lBRS9DLGdEQUFnRDtJQUNoRCxNQUFNLFVBQVUsR0FBRyxJQUFJLEdBQUcsQ0FDeEIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQXVCLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUNqRSxDQUFBO0lBRUQsNENBQTRDO0lBQzVDLE1BQU0sZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNwRCxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUU7UUFDWCxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQW9CO1FBQ3JDLE9BQU8sRUFBRSxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFvQixDQUFDLElBQUksSUFBSTtRQUMxRCxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVU7S0FDNUIsQ0FBQyxDQUFDLENBQUE7SUFFSCxPQUFPLElBQUksNEJBQVksQ0FBQyxFQUFFLFFBQVEsRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUE7QUFDekQsQ0FBQyxDQUNGLENBQUE7QUFFWSxRQUFBLG1CQUFtQixHQUFHLElBQUEsOEJBQWMsRUFDL0MsY0FBYyxFQUNkLENBQUMsS0FBdUIsRUFBdUMsRUFBRTtJQUMvRCxNQUFNLFlBQVksR0FBRyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUNsRCxNQUFNLGdCQUFnQixHQUFHLDRCQUE0QixDQUFDLFlBQVksQ0FBQyxDQUFBO0lBRW5FLE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQztRQUMxQixRQUFRLEVBQUUsZ0JBQWdCLENBQUMsUUFBUTtLQUNwQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQ0YsQ0FBQTtBQUVELGtCQUFlLDJCQUFtQixDQUFBIn0=
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWishlistWorkflow = exports.removeFromWishlistWorkflow = exports.addToWishlistWorkflow = void 0;
4
+ var add_to_wishlist_1 = require("./add-to-wishlist");
5
+ Object.defineProperty(exports, "addToWishlistWorkflow", { enumerable: true, get: function () { return add_to_wishlist_1.addToWishlistWorkflow; } });
6
+ var remove_from_wishlist_1 = require("./remove-from-wishlist");
7
+ Object.defineProperty(exports, "removeFromWishlistWorkflow", { enumerable: true, get: function () { return remove_from_wishlist_1.removeFromWishlistWorkflow; } });
8
+ var get_wishlist_1 = require("./get-wishlist");
9
+ Object.defineProperty(exports, "getWishlistWorkflow", { enumerable: true, get: function () { return get_wishlist_1.getWishlistWorkflow; } });
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFEQUF5RDtBQUFoRCx3SEFBQSxxQkFBcUIsT0FBQTtBQUM5QiwrREFBbUU7QUFBMUQsa0lBQUEsMEJBQTBCLE9BQUE7QUFDbkMsK0NBQW9EO0FBQTNDLG1IQUFBLG1CQUFtQixPQUFBIn0=
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeFromWishlistWorkflow = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const wishlist_1 = require("../modules/wishlist");
6
+ const validateWishlistItemExistsStep = (0, workflows_sdk_1.createStep)("validate-wishlist-item-exists", async (input, { container }) => {
7
+ const wishlistService = container.resolve(wishlist_1.WISHLIST_MODULE);
8
+ const exists = await wishlistService.isInWishlist(input.customer_id, input.product_id);
9
+ if (!exists) {
10
+ throw new Error(`Wishlist item not found for customer ${input.customer_id} and product ${input.product_id}`);
11
+ }
12
+ return new workflows_sdk_1.StepResponse({
13
+ customer_id: input.customer_id,
14
+ product_id: input.product_id,
15
+ });
16
+ });
17
+ const removeFromWishlistStep = (0, workflows_sdk_1.createStep)("remove-from-wishlist", async (input, { container }) => {
18
+ const wishlistService = container.resolve(wishlist_1.WISHLIST_MODULE);
19
+ await wishlistService.removeFromWishlist(input.customer_id, input.product_id);
20
+ return new workflows_sdk_1.StepResponse({ success: true });
21
+ });
22
+ exports.removeFromWishlistWorkflow = (0, workflows_sdk_1.createWorkflow)("remove-from-wishlist", (input) => {
23
+ const validated = validateWishlistItemExistsStep(input);
24
+ const result = removeFromWishlistStep(validated);
25
+ return new workflows_sdk_1.WorkflowResponse({
26
+ success: result.success,
27
+ });
28
+ });
29
+ exports.default = exports.removeFromWishlistWorkflow;
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3ZlLWZyb20td2lzaGxpc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL3JlbW92ZS1mcm9tLXdpc2hsaXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUswQztBQUMxQyxrREFBcUQ7QUFZckQsTUFBTSw4QkFBOEIsR0FBRyxJQUFBLDBCQUFVLEVBQy9DLCtCQUErQixFQUMvQixLQUFLLEVBQUUsS0FBOEIsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7SUFDdEQsTUFBTSxlQUFlLEdBQTBCLFNBQVMsQ0FBQyxPQUFPLENBQzlELDBCQUFlLENBQ2hCLENBQUE7SUFFRCxNQUFNLE1BQU0sR0FBRyxNQUFNLGVBQWUsQ0FBQyxZQUFZLENBQy9DLEtBQUssQ0FBQyxXQUFXLEVBQ2pCLEtBQUssQ0FBQyxVQUFVLENBQ2pCLENBQUE7SUFFRCxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixNQUFNLElBQUksS0FBSyxDQUNiLHdDQUF3QyxLQUFLLENBQUMsV0FBVyxnQkFBZ0IsS0FBSyxDQUFDLFVBQVUsRUFBRSxDQUM1RixDQUFBO0lBQ0gsQ0FBQztJQUVELE9BQU8sSUFBSSw0QkFBWSxDQUFDO1FBQ3RCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztRQUM5QixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7S0FDN0IsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUNGLENBQUE7QUFFRCxNQUFNLHNCQUFzQixHQUFHLElBQUEsMEJBQVUsRUFDdkMsc0JBQXNCLEVBQ3RCLEtBQUssRUFDSCxLQUFrRCxFQUNsRCxFQUFFLFNBQVMsRUFBRSxFQUNiLEVBQUU7SUFDRixNQUFNLGVBQWUsR0FBMEIsU0FBUyxDQUFDLE9BQU8sQ0FDOUQsMEJBQWUsQ0FDaEIsQ0FBQTtJQUVELE1BQU0sZUFBZSxDQUFDLGtCQUFrQixDQUN0QyxLQUFLLENBQUMsV0FBVyxFQUNqQixLQUFLLENBQUMsVUFBVSxDQUNqQixDQUFBO0lBRUQsT0FBTyxJQUFJLDRCQUFZLENBQUMsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQTtBQUM1QyxDQUFDLENBQ0YsQ0FBQTtBQUVZLFFBQUEsMEJBQTBCLEdBQUcsSUFBQSw4QkFBYyxFQUN0RCxzQkFBc0IsRUFDdEIsQ0FDRSxLQUE4QixFQUNjLEVBQUU7SUFDOUMsTUFBTSxTQUFTLEdBQUcsOEJBQThCLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDdkQsTUFBTSxNQUFNLEdBQUcsc0JBQXNCLENBQUMsU0FBUyxDQUFDLENBQUE7SUFFaEQsT0FBTyxJQUFJLGdDQUFnQixDQUFDO1FBQzFCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztLQUN4QixDQUFDLENBQUE7QUFDSixDQUFDLENBQ0YsQ0FBQTtBQUVELGtCQUFlLGtDQUEwQixDQUFBIn0=
package/README.md CHANGED
@@ -34,7 +34,497 @@
34
34
 
35
35
  ## Compatibility
36
36
 
37
- This starter is compatible with versions >= 2.4.0 of `@medusajs/medusa`.
37
+ This plugin is compatible with versions >= 2.4.0 of `@medusajs/medusa`.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ yarn add medusa-product-helper
43
+ # or
44
+ npm install medusa-product-helper
45
+ ```
46
+
47
+ ## Configuration
48
+
49
+ Add the plugin to your `medusa-config.ts`:
50
+
51
+ ```ts
52
+ import type { ConfigModule } from "@medusajs/framework/types"
53
+
54
+ const plugins = [
55
+ {
56
+ resolve: "medusa-product-helper",
57
+ options: {
58
+ // Metadata descriptors for product metadata fields
59
+ metadata: {
60
+ // Expose client-side helper functions for metadata access
61
+ expose_client_helpers: true,
62
+ // Define metadata fields that will be used across products
63
+ descriptors: [
64
+ {
65
+ key: "brand",
66
+ label: "Brand",
67
+ type: "text",
68
+ },
69
+ {
70
+ key: "material",
71
+ label: "Material",
72
+ type: "text",
73
+ },
74
+ {
75
+ key: "warranty_years",
76
+ label: "Warranty (Years)",
77
+ type: "number",
78
+ },
79
+ {
80
+ key: "is_eco_friendly",
81
+ label: "Eco Friendly",
82
+ type: "bool",
83
+ },
84
+ {
85
+ key: "certification_file",
86
+ label: "Certification Document",
87
+ type: "file",
88
+ },
89
+ ],
90
+ },
91
+ // Predefined price ranges for filtering
92
+ price_ranges: [
93
+ {
94
+ label: "Under $50",
95
+ currency_code: "usd",
96
+ min: 0,
97
+ max: 50,
98
+ },
99
+ {
100
+ label: "$50 - $100",
101
+ currency_code: "usd",
102
+ min: 50,
103
+ max: 100,
104
+ },
105
+ {
106
+ label: "$100 - $200",
107
+ currency_code: "usd",
108
+ min: 100,
109
+ max: 200,
110
+ },
111
+ {
112
+ label: "Over $200",
113
+ currency_code: "usd",
114
+ min: 200,
115
+ max: null,
116
+ },
117
+ {
118
+ label: "Custom Range",
119
+ min: null,
120
+ max: null,
121
+ },
122
+ ],
123
+ // Default price range when none is specified
124
+ default_price_range: {
125
+ label: "custom",
126
+ min: null,
127
+ max: null,
128
+ },
129
+ // Promotion window configuration
130
+ promotion_window: {
131
+ // Metadata key that stores the promotion start date
132
+ start_metadata_key: "promotion_start",
133
+ // Metadata key that stores the promotion end date
134
+ end_metadata_key: "promotion_end",
135
+ // If true, promotions without an end date are considered active
136
+ treat_open_ended_as_active: true,
137
+ },
138
+ // Product availability filtering options
139
+ availability: {
140
+ // Only show products that are in stock
141
+ require_in_stock: false,
142
+ // Include products available for preorder
143
+ include_preorder: true,
144
+ // Include products available for backorder
145
+ include_backorder: true,
146
+ // Include gift cards in product listings
147
+ include_gift_cards: false,
148
+ // Only show publishable products
149
+ publishable_only: true,
150
+ },
151
+ // Product rating configuration
152
+ rating: {
153
+ // Enable rating-based filtering
154
+ enabled: true,
155
+ // Minimum rating value (0-5)
156
+ min: 0,
157
+ // Maximum rating value (0-5)
158
+ max: 5,
159
+ // Require products to have at least one review
160
+ require_reviews: false,
161
+ },
162
+ },
163
+ },
164
+ ]
165
+
166
+ export default {
167
+ projectConfig: {
168
+ // Your Medusa project configuration
169
+ // database_url: process.env.DATABASE_URL,
170
+ // ...
171
+ },
172
+ plugins,
173
+ } satisfies ConfigModule
174
+ ```
175
+
176
+ ### Configuration Options
177
+
178
+ #### Metadata
179
+
180
+ Define metadata fields that will be used across your products. Available field types:
181
+ - `text`: String values
182
+ - `number`: Numeric values
183
+ - `bool`: Boolean values
184
+ - `file`: File references
185
+
186
+ #### Price Ranges
187
+
188
+ Define predefined price ranges for filtering. Each range can specify:
189
+ - `label`: Display label for the range
190
+ - `currency_code`: Optional ISO 3-letter currency code (e.g., "usd", "eur")
191
+ - `min`: Minimum price (null for no minimum)
192
+ - `max`: Maximum price (null for no maximum)
193
+
194
+ #### Promotion Window
195
+
196
+ Configure how promotion dates are tracked using product metadata:
197
+ - `start_metadata_key`: Metadata key storing promotion start date
198
+ - `end_metadata_key`: Metadata key storing promotion end date
199
+ - `treat_open_ended_as_active`: If true, promotions without an end date are considered active
200
+
201
+ #### Availability
202
+
203
+ Control which products appear in listings:
204
+ - `require_in_stock`: Only show in-stock products
205
+ - `include_preorder`: Include preorder products
206
+ - `include_backorder`: Include backorder products
207
+ - `include_gift_cards`: Include gift cards
208
+ - `publishable_only`: Only show publishable products
209
+
210
+ #### Rating
211
+
212
+ Configure rating-based filtering:
213
+ - `enabled`: Enable rating filtering
214
+ - `min`: Minimum rating (0-5)
215
+ - `max`: Maximum rating (0-5)
216
+ - `require_reviews`: Require at least one review
217
+
218
+ ## Wishlist Feature
219
+
220
+ The plugin includes a comprehensive wishlist feature that allows customers to save products they're interested in and admins to view wishlist statistics.
221
+
222
+ ### Module Registration
223
+
224
+ The wishlist module is automatically registered when you add the plugin to your Medusa configuration. No additional configuration is required for basic usage.
225
+
226
+ ### Database Migration
227
+
228
+ After installing the plugin, generate and run the database migration:
229
+
230
+ ```bash
231
+ npx medusa plugin:db:generate
232
+ npx medusa db:migrate
233
+ ```
234
+
235
+ This will create the `wishlist` table with the following structure:
236
+ - `id`: Primary key
237
+ - `customer_id`: Customer identifier (searchable)
238
+ - `product_id`: Product identifier (searchable)
239
+ - `created_at`: Timestamp when item was added
240
+ - `updated_at`: Timestamp when item was last updated
241
+
242
+ The table enforces a unique constraint on the combination of `customer_id` and `product_id`, ensuring no duplicate entries.
243
+
244
+ ### Store API Endpoints
245
+
246
+ #### Add Product to Wishlist
247
+
248
+ **POST** `/store/wishlist`
249
+
250
+ Add a product to the current customer's wishlist. The operation is idempotent - adding the same product multiple times will not create duplicates.
251
+
252
+ **Authentication**: Required (customer must be authenticated)
253
+
254
+ **Request Body**:
255
+ ```json
256
+ {
257
+ "product_id": "prod_123"
258
+ }
259
+ ```
260
+
261
+ **Response**:
262
+ ```json
263
+ {
264
+ "wishlist_item": {
265
+ "id": "wish_123",
266
+ "customer_id": "cus_123",
267
+ "product_id": "prod_123",
268
+ "created_at": "2024-01-01T00:00:00.000Z",
269
+ "updated_at": "2024-01-01T00:00:00.000Z"
270
+ }
271
+ }
272
+ ```
273
+
274
+ **Example**:
275
+ ```bash
276
+ curl -X POST https://your-store.com/store/wishlist \
277
+ -H "Authorization: Bearer YOUR_TOKEN" \
278
+ -H "Content-Type: application/json" \
279
+ -d '{"product_id": "prod_123"}'
280
+ ```
281
+
282
+ #### Remove Product from Wishlist
283
+
284
+ **DELETE** `/store/wishlist/:product_id`
285
+
286
+ Remove a product from the current customer's wishlist.
287
+
288
+ **Authentication**: Required (customer must be authenticated)
289
+
290
+ **Response**:
291
+ ```json
292
+ {
293
+ "success": true
294
+ }
295
+ ```
296
+
297
+ **Example**:
298
+ ```bash
299
+ curl -X DELETE https://your-store.com/store/wishlist/prod_123 \
300
+ -H "Authorization: Bearer YOUR_TOKEN"
301
+ ```
302
+
303
+ #### Get Customer Wishlist
304
+
305
+ **GET** `/store/wishlist`
306
+
307
+ Get the current customer's wishlist. Can return either product IDs only or full product details.
308
+
309
+ **Authentication**: Required (customer must be authenticated)
310
+
311
+ **Query Parameters**:
312
+ - `include_details` (boolean, default: `false`): If `true`, returns full product details. If `false`, returns only product IDs.
313
+
314
+ **Response (IDs only)**:
315
+ ```json
316
+ {
317
+ "wishlist": [
318
+ {
319
+ "product_id": "prod_123"
320
+ },
321
+ {
322
+ "product_id": "prod_456"
323
+ }
324
+ ]
325
+ }
326
+ ```
327
+
328
+ **Response (with details)**:
329
+ ```json
330
+ {
331
+ "wishlist": [
332
+ {
333
+ "id": "wish_123",
334
+ "product_id": "prod_123",
335
+ "product": {
336
+ "id": "prod_123",
337
+ "title": "Product Name",
338
+ "handle": "product-name",
339
+ "description": "Product description",
340
+ "thumbnail": "https://example.com/image.jpg",
341
+ "status": "published",
342
+ "created_at": "2024-01-01T00:00:00.000Z",
343
+ "updated_at": "2024-01-01T00:00:00.000Z"
344
+ },
345
+ "created_at": "2024-01-01T00:00:00.000Z"
346
+ }
347
+ ]
348
+ }
349
+ ```
350
+
351
+ **Example**:
352
+ ```bash
353
+ # Get only product IDs
354
+ curl https://your-store.com/store/wishlist \
355
+ -H "Authorization: Bearer YOUR_TOKEN"
356
+
357
+ # Get full product details
358
+ curl "https://your-store.com/store/wishlist?include_details=true" \
359
+ -H "Authorization: Bearer YOUR_TOKEN"
360
+ ```
361
+
362
+ ### Admin API Endpoints
363
+
364
+ #### Get Wishlist Statistics
365
+
366
+ **GET** `/admin/wishlist/stats`
367
+
368
+ Get wishlist statistics showing how many users have added each product to their wishlist.
369
+
370
+ **Authentication**: Required (admin authentication)
371
+
372
+ **Query Parameters**:
373
+ - `product_id` (string, optional): If provided, returns the wishlist count for that specific product only.
374
+
375
+ **Response (all products)**:
376
+ ```json
377
+ {
378
+ "stats": [
379
+ {
380
+ "product_id": "prod_123",
381
+ "wishlist_count": 42
382
+ },
383
+ {
384
+ "product_id": "prod_456",
385
+ "wishlist_count": 15
386
+ }
387
+ ]
388
+ }
389
+ ```
390
+
391
+ **Response (single product)**:
392
+ ```json
393
+ {
394
+ "product_id": "prod_123",
395
+ "wishlist_count": 42
396
+ }
397
+ ```
398
+
399
+ **Example**:
400
+ ```bash
401
+ # Get statistics for all products
402
+ curl https://your-store.com/admin/wishlist/stats \
403
+ -H "Authorization: Bearer ADMIN_TOKEN"
404
+
405
+ # Get statistics for a specific product
406
+ curl "https://your-store.com/admin/wishlist/stats?product_id=prod_123" \
407
+ -H "Authorization: Bearer ADMIN_TOKEN"
408
+ ```
409
+
410
+ ### Helper Function
411
+
412
+ The plugin provides a helper function that can be used directly by UI components without implementing the entire logic.
413
+
414
+ #### Import the Helper
415
+
416
+ ```typescript
417
+ import { getWishlist } from "medusa-product-helper/wishlist-helper"
418
+ ```
419
+
420
+ #### Usage Examples
421
+
422
+ **Get only product IDs**:
423
+ ```typescript
424
+ import { getWishlist } from "medusa-product-helper/wishlist-helper"
425
+
426
+ // In your component or service
427
+ const productIds = await getWishlist(container, customerId)
428
+ // Returns: ['prod_123', 'prod_456']
429
+ ```
430
+
431
+ **Get full product details**:
432
+ ```typescript
433
+ import { getWishlist } from "medusa-product-helper/wishlist-helper"
434
+
435
+ const wishlist = await getWishlist(container, customerId, {
436
+ includeDetails: true
437
+ })
438
+ // Returns: [
439
+ // {
440
+ // product_id: 'prod_123',
441
+ // product: { ... },
442
+ // id: 'wish_123',
443
+ // created_at: Date
444
+ // },
445
+ // ...
446
+ // ]
447
+ ```
448
+
449
+ **Filter by specific products**:
450
+ ```typescript
451
+ import { getWishlist } from "medusa-product-helper/wishlist-helper"
452
+
453
+ const wishlist = await getWishlist(container, customerId, {
454
+ includeDetails: true,
455
+ productIds: ['prod_123', 'prod_456']
456
+ })
457
+ ```
458
+
459
+ #### Helper Options
460
+
461
+ - `includeDetails` (boolean, default: `false`): If `true`, returns full product details. If `false`, returns only product IDs.
462
+ - `productIds` (string[], optional): Filter wishlist by specific product IDs.
463
+
464
+ ### Using Workflows Directly
465
+
466
+ You can also use the workflows directly in your custom code:
467
+
468
+ ```typescript
469
+ import { addToWishlistWorkflow } from "medusa-product-helper/workflows"
470
+ import { removeFromWishlistWorkflow } from "medusa-product-helper/workflows"
471
+ import { getWishlistWorkflow } from "medusa-product-helper/workflows"
472
+
473
+ // Add to wishlist
474
+ const { result } = await addToWishlistWorkflow(container).run({
475
+ input: {
476
+ customer_id: "cus_123",
477
+ product_id: "prod_123"
478
+ }
479
+ })
480
+
481
+ // Remove from wishlist
482
+ const { result } = await removeFromWishlistWorkflow(container).run({
483
+ input: {
484
+ customer_id: "cus_123",
485
+ product_id: "prod_123"
486
+ }
487
+ })
488
+
489
+ // Get wishlist
490
+ const { result } = await getWishlistWorkflow(container).run({
491
+ input: {
492
+ customer_id: "cus_123",
493
+ options: {
494
+ includeDetails: true
495
+ }
496
+ }
497
+ })
498
+ ```
499
+
500
+ ### Using the Module Service Directly
501
+
502
+ You can also access the wishlist module service directly:
503
+
504
+ ```typescript
505
+ import { WISHLIST_MODULE } from "medusa-product-helper/modules/wishlist"
506
+ import type { WishlistModuleService } from "medusa-product-helper/modules/wishlist"
507
+
508
+ // In your route or service
509
+ const wishlistService: WishlistModuleService = container.resolve(WISHLIST_MODULE)
510
+
511
+ // Add to wishlist
512
+ await wishlistService.addToWishlist(customerId, productId)
513
+
514
+ // Remove from wishlist
515
+ await wishlistService.removeFromWishlist(customerId, productId)
516
+
517
+ // Get wishlist
518
+ const wishlist = await wishlistService.getWishlist(customerId, {
519
+ includeDetails: true
520
+ })
521
+
522
+ // Check if product is in wishlist
523
+ const isInWishlist = await wishlistService.isInWishlist(customerId, productId)
524
+
525
+ // Get wishlist counts (for admin)
526
+ const counts = await wishlistService.getWishlistCounts(['prod_123', 'prod_456'])
527
+ ```
38
528
 
39
529
  ## Getting Started
40
530
 
@@ -42,8 +532,6 @@ Visit the [Quickstart Guide](https://docs.medusajs.com/learn/installation) to se
42
532
 
43
533
  Visit the [Plugins documentation](https://docs.medusajs.com/learn/fundamentals/plugins) to learn more about plugins and how to create them.
44
534
 
45
- Visit the [Docs](https://docs.medusajs.com/learn/installation#get-started) to learn more about our system requirements.
46
-
47
535
  ## What is Medusa
48
536
 
49
537
  Medusa is a set of commerce modules and tools that allow you to build rich, reliable, and performant commerce applications without reinventing core commerce logic. The modules can be customized and used to build advanced ecommerce stores, marketplaces, or any product that needs foundational commerce primitives. All modules are open-source and freely available on npm.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-product-helper",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A starter for Medusa plugins.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",
@@ -13,6 +13,7 @@
13
13
  "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
14
14
  "./modules/*": "./.medusa/server/src/modules/*/index.js",
15
15
  "./providers/*": "./.medusa/server/src/providers/*/index.js",
16
+ "./wishlist-helper": "./.medusa/server/src/shared/wishlist/index.js",
16
17
  "./*": "./.medusa/server/src/*.js",
17
18
  "./admin": {
18
19
  "import": "./.medusa/server/src/admin/index.mjs",