@lodashventure/medusa-brand 1.1.11 → 1.1.13

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.
Files changed (56) hide show
  1. package/.medusa/server/api/admin/brands/[id]/image/route.js +119 -0
  2. package/.medusa/server/api/admin/brands/[id]/logo/route.js +119 -0
  3. package/.medusa/server/api/admin/brands/[id]/products/route.js +52 -0
  4. package/.medusa/server/api/admin/brands/[id]/route.js +112 -0
  5. package/.medusa/server/api/admin/brands/route.js +76 -0
  6. package/.medusa/server/api/admin/products/[id]/brand/route.js +117 -0
  7. package/{dist → .medusa/server}/api/middlewares/attach-brand-to-products.js +1 -0
  8. package/{dist → .medusa/server}/api/middlewares.js +1 -0
  9. package/.medusa/server/api/store/brands/route.js +53 -0
  10. package/{dist → .medusa/server}/index.js +1 -0
  11. package/{dist → .medusa/server}/modules/brand/index.js +1 -0
  12. package/{dist → .medusa/server}/modules/brand/migrations/Migration20251021070648.js +1 -0
  13. package/.medusa/server/modules/brand/models/brand.js +43 -0
  14. package/.medusa/server/modules/brand/service.js +11 -0
  15. package/.medusa/server/services/gcs-direct-upload.js +55 -0
  16. package/.medusa/server/src/admin/index.js +972 -0
  17. package/.medusa/server/src/admin/index.mjs +971 -0
  18. package/.medusa/server/workflows/upload-brand-image.js +57 -0
  19. package/package.json +14 -13
  20. package/dist/admin/components/brand-form.d.ts +0 -19
  21. package/dist/admin/components/brand-form.js +0 -182
  22. package/dist/admin/components/brand-image-uploader.d.ts +0 -14
  23. package/dist/admin/components/brand-image-uploader.js +0 -217
  24. package/dist/admin/lib/sdk.d.ts +0 -1
  25. package/dist/admin/lib/sdk.js +0 -14
  26. package/dist/admin/routes/brands/page.d.ts +0 -4
  27. package/dist/admin/routes/brands/page.js +0 -253
  28. package/dist/admin/widgets/product-brand-widget.d.ts +0 -8
  29. package/dist/admin/widgets/product-brand-widget.js +0 -207
  30. package/dist/api/admin/brands/[id]/image/route.js +0 -118
  31. package/dist/api/admin/brands/[id]/logo/route.js +0 -118
  32. package/dist/api/admin/brands/[id]/products/route.js +0 -51
  33. package/dist/api/admin/brands/[id]/route.js +0 -111
  34. package/dist/api/admin/brands/route.js +0 -75
  35. package/dist/api/admin/products/[id]/brand/route.js +0 -116
  36. package/dist/api/store/brands/route.js +0 -50
  37. package/dist/modules/brand/models/brand.js +0 -42
  38. package/dist/modules/brand/service.js +0 -10
  39. package/dist/services/gcs-direct-upload.js +0 -54
  40. package/dist/workflows/upload-brand-image.js +0 -56
  41. /package/{dist → .medusa/server}/api/admin/brands/[id]/image/route.d.ts +0 -0
  42. /package/{dist → .medusa/server}/api/admin/brands/[id]/logo/route.d.ts +0 -0
  43. /package/{dist → .medusa/server}/api/admin/brands/[id]/products/route.d.ts +0 -0
  44. /package/{dist → .medusa/server}/api/admin/brands/[id]/route.d.ts +0 -0
  45. /package/{dist → .medusa/server}/api/admin/brands/route.d.ts +0 -0
  46. /package/{dist → .medusa/server}/api/admin/products/[id]/brand/route.d.ts +0 -0
  47. /package/{dist → .medusa/server}/api/middlewares/attach-brand-to-products.d.ts +0 -0
  48. /package/{dist → .medusa/server}/api/middlewares.d.ts +0 -0
  49. /package/{dist → .medusa/server}/api/store/brands/route.d.ts +0 -0
  50. /package/{dist → .medusa/server}/index.d.ts +0 -0
  51. /package/{dist → .medusa/server}/modules/brand/index.d.ts +0 -0
  52. /package/{dist → .medusa/server}/modules/brand/migrations/Migration20251021070648.d.ts +0 -0
  53. /package/{dist → .medusa/server}/modules/brand/models/brand.d.ts +0 -0
  54. /package/{dist → .medusa/server}/modules/brand/service.d.ts +0 -0
  55. /package/{dist → .medusa/server}/services/gcs-direct-upload.d.ts +0 -0
  56. /package/{dist → .medusa/server}/workflows/upload-brand-image.d.ts +0 -0
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadBrandImageWorkflow = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const gcs_direct_upload_1 = require("../services/gcs-direct-upload");
6
+ const uploadBrandImageStep = (0, workflows_sdk_1.createStep)("upload-brand-image-step", async ({ brandId, imageType, fileData }, { container }) => {
7
+ const brandService = container.resolve("brandCustom");
8
+ const gcsUploadService = new gcs_direct_upload_1.GcsDirectUploadService();
9
+ // Generate unique filename for direct upload
10
+ const timestamp = Date.now();
11
+ const ext = fileData.filename.split('.').pop() || 'jpg';
12
+ const filename = `brands/${imageType}-${brandId}-${timestamp}.${ext}`;
13
+ // Convert base64 to buffer
14
+ const buffer = Buffer.from(fileData.content, "base64");
15
+ // Upload directly to GCS
16
+ const publicUrl = await gcsUploadService.uploadFile(filename, buffer, fileData.mimeType);
17
+ // Retrieve existing brand
18
+ const brand = await brandService.retrieveBrand(brandId);
19
+ if (!brand) {
20
+ throw new Error(`Brand with id ${brandId} not found`);
21
+ }
22
+ // Delete old image if it exists
23
+ const oldImageUrl = brand[imageType];
24
+ if (oldImageUrl) {
25
+ try {
26
+ if (oldImageUrl.includes('storage.googleapis.com')) {
27
+ const parts = oldImageUrl.split('/');
28
+ const bucketIndex = parts.indexOf('sangaroon');
29
+ if (bucketIndex !== -1 && bucketIndex < parts.length - 1) {
30
+ const oldFilename = parts.slice(bucketIndex + 1).join('/');
31
+ await gcsUploadService.deleteFile(oldFilename);
32
+ }
33
+ }
34
+ }
35
+ catch (error) {
36
+ console.error(`Failed to delete old ${imageType}:`, error);
37
+ // Continue even if deletion fails
38
+ }
39
+ }
40
+ // Update brand with new image URL
41
+ const updateData = {};
42
+ updateData[imageType] = publicUrl;
43
+ await brandService.updateBrands([{
44
+ id: brandId,
45
+ ...updateData
46
+ }]);
47
+ return new workflows_sdk_1.StepResponse({
48
+ brandId,
49
+ imageType,
50
+ imageUrl: publicUrl,
51
+ });
52
+ });
53
+ exports.uploadBrandImageWorkflow = (0, workflows_sdk_1.createWorkflow)("upload-brand-image", (input) => {
54
+ const result = uploadBrandImageStep(input);
55
+ return new workflows_sdk_1.WorkflowResponse(result);
56
+ });
57
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBsb2FkLWJyYW5kLWltYWdlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3dvcmtmbG93cy91cGxvYWQtYnJhbmQtaW1hZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBTTJDO0FBQzNDLHFFQUF1RTtBQVl2RSxNQUFNLG9CQUFvQixHQUFHLElBQUEsMEJBQVUsRUFDckMseUJBQXlCLEVBQ3pCLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUF5QixFQUFFLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRTtJQUMvRSxNQUFNLFlBQVksR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBUSxDQUFDO0lBQzdELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSwwQ0FBc0IsRUFBRSxDQUFDO0lBRXRELDZDQUE2QztJQUM3QyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDN0IsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksS0FBSyxDQUFDO0lBQ3hELE1BQU0sUUFBUSxHQUFHLFVBQVUsU0FBUyxJQUFJLE9BQU8sSUFBSSxTQUFTLElBQUksR0FBRyxFQUFFLENBQUM7SUFFdEUsMkJBQTJCO0lBQzNCLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztJQUV2RCx5QkFBeUI7SUFDekIsTUFBTSxTQUFTLEdBQUcsTUFBTSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFekYsMEJBQTBCO0lBQzFCLE1BQU0sS0FBSyxHQUFHLE1BQU0sWUFBWSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUV4RCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixPQUFPLFlBQVksQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFRCxnQ0FBZ0M7SUFDaEMsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3JDLElBQUksV0FBVyxFQUFFLENBQUM7UUFDaEIsSUFBSSxDQUFDO1lBQ0gsSUFBSSxXQUFXLENBQUMsUUFBUSxDQUFDLHdCQUF3QixDQUFDLEVBQUUsQ0FBQztnQkFDbkQsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDckMsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDL0MsSUFBSSxXQUFXLEtBQUssQ0FBQyxDQUFDLElBQUksV0FBVyxHQUFHLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3pELE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztvQkFDM0QsTUFBTSxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQ2pELENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHdCQUF3QixTQUFTLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMzRCxrQ0FBa0M7UUFDcEMsQ0FBQztJQUNILENBQUM7SUFFRCxrQ0FBa0M7SUFDbEMsTUFBTSxVQUFVLEdBQVEsRUFBRSxDQUFDO0lBQzNCLFVBQVUsQ0FBQyxTQUFTLENBQUMsR0FBRyxTQUFTLENBQUM7SUFFbEMsTUFBTSxZQUFZLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDL0IsRUFBRSxFQUFFLE9BQU87WUFDWCxHQUFHLFVBQVU7U0FDZCxDQUFDLENBQUMsQ0FBQztJQUVKLE9BQU8sSUFBSSw0QkFBWSxDQUFDO1FBQ3RCLE9BQU87UUFDUCxTQUFTO1FBQ1QsUUFBUSxFQUFFLFNBQVM7S0FDcEIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUNGLENBQUM7QUFFVyxRQUFBLHdCQUF3QixHQUFHLElBQUEsOEJBQWMsRUFDcEQsb0JBQW9CLEVBQ3BCLENBQUMsS0FBMEMsRUFBRSxFQUFFO0lBQzdDLE1BQU0sTUFBTSxHQUFHLG9CQUFvQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNDLE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUN0QyxDQUFDLENBQ0YsQ0FBQyJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lodashventure/medusa-brand",
3
- "version": "1.1.11",
3
+ "version": "1.1.13",
4
4
  "description": "Brand management plugin for Medusa v2",
5
5
  "author": "Lodashventure",
6
6
  "license": "MIT",
@@ -10,24 +10,25 @@
10
10
  "brand",
11
11
  "ecommerce"
12
12
  ],
13
- "main": "dist/index.js",
13
+ "files": [
14
+ ".medusa/server"
15
+ ],
14
16
  "exports": {
15
- ".": "./dist/index.js",
16
- "./modules/brand": "./dist/modules/brand/index.js",
17
- "./package.json": "./package.json"
17
+ "./package.json": "./package.json",
18
+ "./workflows": "./.medusa/server/src/workflows/index.js",
19
+ "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
20
+ "./modules/*": "./.medusa/server/src/modules/*/index.js",
21
+ "./providers/*": "./.medusa/server/src/providers/*/index.js",
22
+ "./admin": "./.medusa/server/src/admin/index.mjs",
23
+ "./*": "./.medusa/server/src/*.js"
18
24
  },
19
25
  "repository": {
20
26
  "type": "git",
21
27
  "url": "https://github.com/lodashventure/medusa-brand"
22
28
  },
23
- "files": [
24
- "dist",
25
- "admin"
26
- ],
27
29
  "scripts": {
28
- "build": "tsc --build",
29
- "watch": "tsc --watch",
30
- "dev": "tsc --watch"
30
+ "build": "medusa plugin:build",
31
+ "dev": "medusa plugin:develop"
31
32
  },
32
33
  "dependencies": {
33
34
  "@google-cloud/storage": "^7.17.2",
@@ -55,4 +56,4 @@
55
56
  "typescript": "^5.6.2",
56
57
  "yalc": "1.0.0-pre.53"
57
58
  }
58
- }
59
+ }
@@ -1,19 +0,0 @@
1
- import React from "react";
2
- interface Brand {
3
- id: string;
4
- name: string;
5
- slug: string;
6
- description?: string;
7
- image?: string;
8
- logo?: string;
9
- website?: string;
10
- is_active: boolean;
11
- metadata?: any;
12
- }
13
- interface BrandFormProps {
14
- brand?: Brand | null;
15
- isCreating: boolean;
16
- onClose: () => void;
17
- }
18
- export declare const BrandForm: ({ brand, isCreating, onClose }: BrandFormProps) => React.JSX.Element;
19
- export {};
@@ -1,182 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.BrandForm = void 0;
37
- const react_1 = __importStar(require("react"));
38
- const sdk_1 = require("../lib/sdk");
39
- if (["$(basename $file)" = "page.tsx"] || "../lib/sdk")
40
- ;
41
- const ui_1 = require("@medusajs/ui");
42
- const icons_1 = require("@medusajs/icons");
43
- const BrandForm = ({ brand, isCreating, onClose }) => {
44
- const [formData, setFormData] = (0, react_1.useState)({
45
- name: "",
46
- slug: "",
47
- description: "",
48
- website: "",
49
- is_active: true,
50
- metadata: {},
51
- });
52
- const [loading, setLoading] = (0, react_1.useState)(false);
53
- const [error, setError] = (0, react_1.useState)(null);
54
- const [slugError, setSlugError] = (0, react_1.useState)(null);
55
- (0, react_1.useEffect)(() => {
56
- if (brand) {
57
- setFormData({
58
- name: brand.name || "",
59
- slug: brand.slug || "",
60
- description: brand.description || "",
61
- website: brand.website || "",
62
- is_active: brand.is_active !== false,
63
- metadata: brand.metadata || {},
64
- });
65
- }
66
- }, [brand]);
67
- const generateSlug = (name) => {
68
- return name
69
- .toLowerCase()
70
- .replace(/[^a-z0-9]+/g, "-")
71
- .replace(/^-+|-+$/g, "");
72
- };
73
- const handleNameChange = (value) => {
74
- setFormData(prev => ({
75
- ...prev,
76
- name: value,
77
- slug: isCreating ? generateSlug(value) : prev.slug,
78
- }));
79
- };
80
- const handleSlugChange = (value) => {
81
- const cleanSlug = value
82
- .toLowerCase()
83
- .replace(/[^a-z0-9-]/g, "")
84
- .replace(/--+/g, "-");
85
- setFormData(prev => ({ ...prev, slug: cleanSlug }));
86
- // Clear slug error when user types
87
- if (slugError)
88
- setSlugError(null);
89
- };
90
- const validateForm = () => {
91
- if (!formData.name.trim()) {
92
- setError("Brand name is required");
93
- return false;
94
- }
95
- if (!formData.slug.trim()) {
96
- setError("Brand slug is required");
97
- return false;
98
- }
99
- if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(formData.slug)) {
100
- setSlugError("Slug must contain only lowercase letters, numbers, and hyphens");
101
- return false;
102
- }
103
- if (formData.website && !formData.website.match(/^https?:\/\/.+/)) {
104
- setError("Website must be a valid URL (starting with http:// or https://)");
105
- return false;
106
- }
107
- return true;
108
- };
109
- const handleSubmit = async (e) => {
110
- e.preventDefault();
111
- if (!validateForm())
112
- return;
113
- setLoading(true);
114
- setError(null);
115
- try {
116
- const url = isCreating
117
- ? "/admin/brands"
118
- : `/admin/brands/${brand?.id}`;
119
- const method = isCreating ? "POST" : "PUT";
120
- const response = await sdk_1.sdk.client.fetch(url, {
121
- method,
122
- headers: {
123
- "Content-Type": "application/json",
124
- },
125
- body: JSON.stringify(formData),
126
- });
127
- const data = await response.json();
128
- if (response.ok) {
129
- onClose();
130
- }
131
- else {
132
- setError(data.error || "Failed to save brand");
133
- if (data.error?.includes("slug")) {
134
- setSlugError("This slug is already in use");
135
- }
136
- }
137
- }
138
- catch (err) {
139
- setError("An error occurred while saving the brand");
140
- console.error("Error saving brand:", err);
141
- }
142
- finally {
143
- setLoading(false);
144
- }
145
- };
146
- return (react_1.default.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50" },
147
- react_1.default.createElement("div", { className: "w-full max-w-2xl rounded-lg bg-ui-bg-base p-6 max-h-[90vh] overflow-y-auto" },
148
- react_1.default.createElement("div", { className: "mb-6 flex items-center justify-between" },
149
- react_1.default.createElement("div", null,
150
- react_1.default.createElement(ui_1.Heading, { level: "h2" }, isCreating ? "Create New Brand" : "Edit Brand"),
151
- !isCreating && brand && (react_1.default.createElement(ui_1.Text, { className: "text-ui-fg-subtle" },
152
- "Editing: ",
153
- brand.name))),
154
- react_1.default.createElement(ui_1.Button, { variant: "secondary", size: "small", onClick: onClose },
155
- react_1.default.createElement(icons_1.X, null))),
156
- error && (react_1.default.createElement(ui_1.Alert, { variant: "error", dismissible: true, className: "mb-4" }, error)),
157
- react_1.default.createElement("form", { onSubmit: handleSubmit, className: "space-y-4" },
158
- react_1.default.createElement("div", null,
159
- react_1.default.createElement(ui_1.Label, { htmlFor: "name", className: "mb-2" }, "Brand Name *"),
160
- react_1.default.createElement(ui_1.Input, { id: "name", placeholder: "e.g., Nike", value: formData.name, onChange: (e) => handleNameChange(e.target.value), required: true })),
161
- react_1.default.createElement("div", null,
162
- react_1.default.createElement(ui_1.Label, { htmlFor: "slug", className: "mb-2" }, "Slug *"),
163
- react_1.default.createElement(ui_1.Input, { id: "slug", placeholder: "e.g., nike", value: formData.slug, onChange: (e) => handleSlugChange(e.target.value), required: true }),
164
- slugError && (react_1.default.createElement(ui_1.Text, { className: "mt-1 text-sm text-ui-fg-error" }, slugError)),
165
- react_1.default.createElement(ui_1.Text, { className: "mt-1 text-xs text-ui-fg-subtle" }, "Used in URLs and must be unique")),
166
- react_1.default.createElement("div", null,
167
- react_1.default.createElement(ui_1.Label, { htmlFor: "description", className: "mb-2" }, "Description"),
168
- react_1.default.createElement(ui_1.Textarea, { id: "description", placeholder: "Enter brand description...", value: formData.description, onChange: (e) => setFormData(prev => ({ ...prev, description: e.target.value })), rows: 4 })),
169
- react_1.default.createElement("div", null,
170
- react_1.default.createElement(ui_1.Label, { htmlFor: "website", className: "mb-2" }, "Website"),
171
- react_1.default.createElement(ui_1.Input, { id: "website", type: "url", placeholder: "https://example.com", value: formData.website, onChange: (e) => setFormData(prev => ({ ...prev, website: e.target.value })) }),
172
- react_1.default.createElement(ui_1.Text, { className: "mt-1 text-xs text-ui-fg-subtle" }, "Include the full URL with http:// or https://")),
173
- react_1.default.createElement("div", { className: "flex items-center justify-between rounded-lg border p-4" },
174
- react_1.default.createElement("div", null,
175
- react_1.default.createElement(ui_1.Label, { htmlFor: "is_active", className: "font-medium" }, "Active Status"),
176
- react_1.default.createElement(ui_1.Text, { className: "text-sm text-ui-fg-subtle" }, "Active brands are visible in your store")),
177
- react_1.default.createElement(ui_1.Switch, { id: "is_active", checked: formData.is_active, onCheckedChange: (checked) => setFormData(prev => ({ ...prev, is_active: checked })) })),
178
- react_1.default.createElement("div", { className: "flex items-center justify-end gap-3 pt-4 border-t" },
179
- react_1.default.createElement(ui_1.Button, { type: "button", variant: "secondary", onClick: onClose }, "Cancel"),
180
- react_1.default.createElement(ui_1.Button, { type: "submit", disabled: loading }, loading ? "Saving..." : isCreating ? "Create Brand" : "Update Brand"))))));
181
- };
182
- exports.BrandForm = BrandForm;
@@ -1,14 +0,0 @@
1
- import React from "react";
2
- interface Brand {
3
- id: string;
4
- name: string;
5
- image?: string;
6
- logo?: string;
7
- }
8
- interface BrandImageUploaderProps {
9
- brand: Brand;
10
- imageType: "image" | "logo";
11
- onClose: () => void;
12
- }
13
- export declare const BrandImageUploader: ({ brand, imageType, onClose, }: BrandImageUploaderProps) => React.JSX.Element;
14
- export {};
@@ -1,217 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.BrandImageUploader = void 0;
37
- const react_1 = __importStar(require("react"));
38
- const sdk_1 = require("../lib/sdk");
39
- if (["$(basename $file)" = "page.tsx"] || "../lib/sdk")
40
- ;
41
- const ui_1 = require("@medusajs/ui");
42
- const icons_1 = require("@medusajs/icons");
43
- const BrandImageUploader = ({ brand, imageType, onClose, }) => {
44
- const currentImage = imageType === "image" ? brand.image : brand.logo;
45
- const [displayImage, setDisplayImage] = (0, react_1.useState)(currentImage || null);
46
- const [isUploading, setIsUploading] = (0, react_1.useState)(false);
47
- const [isDragging, setIsDragging] = (0, react_1.useState)(false);
48
- const [error, setError] = (0, react_1.useState)(null);
49
- const [previewUrl, setPreviewUrl] = (0, react_1.useState)(null);
50
- const isLogo = imageType === "logo";
51
- const maxSize = isLogo ? 2 : 5; // 2MB for logos, 5MB for images
52
- const allowedTypes = isLogo
53
- ? ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml"]
54
- : ["image/jpeg", "image/png", "image/gif", "image/webp"];
55
- const formatFileTypes = () => {
56
- return isLogo
57
- ? "JPEG, PNG, GIF, WebP, or SVG"
58
- : "JPEG, PNG, GIF, or WebP";
59
- };
60
- const validateFile = (file) => {
61
- if (!allowedTypes.includes(file.type)) {
62
- setError(`Please upload a valid image file (${formatFileTypes()})`);
63
- return false;
64
- }
65
- if (file.size > maxSize * 1024 * 1024) {
66
- setError(`File size must be less than ${maxSize}MB`);
67
- return false;
68
- }
69
- return true;
70
- };
71
- const handleFileUpload = async (file) => {
72
- if (!validateFile(file))
73
- return;
74
- setError(null);
75
- // Show preview immediately
76
- const reader = new FileReader();
77
- reader.onloadend = () => {
78
- setPreviewUrl(reader.result);
79
- };
80
- reader.readAsDataURL(file);
81
- // Upload to server
82
- setIsUploading(true);
83
- const formData = new FormData();
84
- formData.append("file", file);
85
- try {
86
- const response = await sdk_1.sdk.client.fetch(`/admin/brands/${brand.id}/${imageType}`, {
87
- method: "POST",
88
- body: formData,
89
- });
90
- if (response.ok) {
91
- const result = await response.json();
92
- const newImageUrl = result.brand[imageType];
93
- setDisplayImage(newImageUrl);
94
- setPreviewUrl(null);
95
- // Show success for a moment before closing
96
- setTimeout(() => {
97
- onClose();
98
- }, 1000);
99
- }
100
- else {
101
- const errorData = await response.json();
102
- setError(errorData.error || `Failed to upload ${imageType}`);
103
- setPreviewUrl(null);
104
- }
105
- }
106
- catch (err) {
107
- setError(`Error uploading ${imageType}`);
108
- setPreviewUrl(null);
109
- console.error(`Error uploading ${imageType}:`, err);
110
- }
111
- finally {
112
- setIsUploading(false);
113
- }
114
- };
115
- const handleDelete = async () => {
116
- if (!confirm(`Are you sure you want to delete the ${imageType}?`))
117
- return;
118
- setIsUploading(true);
119
- setError(null);
120
- try {
121
- const response = await sdk_1.sdk.client.fetch(`/admin/brands/${brand.id}/${imageType}`, {
122
- method: "DELETE",
123
- });
124
- if (response.ok) {
125
- setDisplayImage(null);
126
- setPreviewUrl(null);
127
- setTimeout(() => {
128
- onClose();
129
- }, 500);
130
- }
131
- else {
132
- const errorData = await response.json();
133
- setError(errorData.error || `Failed to delete ${imageType}`);
134
- }
135
- }
136
- catch (err) {
137
- setError(`Error deleting ${imageType}`);
138
- console.error(`Error deleting ${imageType}:`, err);
139
- }
140
- finally {
141
- setIsUploading(false);
142
- }
143
- };
144
- const handleDragEnter = (0, react_1.useCallback)((e) => {
145
- e.preventDefault();
146
- e.stopPropagation();
147
- setIsDragging(true);
148
- }, []);
149
- const handleDragLeave = (0, react_1.useCallback)((e) => {
150
- e.preventDefault();
151
- e.stopPropagation();
152
- setIsDragging(false);
153
- }, []);
154
- const handleDragOver = (0, react_1.useCallback)((e) => {
155
- e.preventDefault();
156
- e.stopPropagation();
157
- }, []);
158
- const handleDrop = (0, react_1.useCallback)((e) => {
159
- e.preventDefault();
160
- e.stopPropagation();
161
- setIsDragging(false);
162
- const file = e.dataTransfer.files?.[0];
163
- if (file) {
164
- handleFileUpload(file);
165
- }
166
- }, []);
167
- const imageToDisplay = previewUrl || displayImage;
168
- return (react_1.default.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50" },
169
- react_1.default.createElement("div", { className: "w-full max-w-2xl rounded-lg bg-ui-bg-base p-6" },
170
- react_1.default.createElement("div", { className: "mb-6 flex items-center justify-between" },
171
- react_1.default.createElement("div", null,
172
- react_1.default.createElement(ui_1.Heading, { level: "h2" },
173
- "Upload Brand ",
174
- isLogo ? "Logo" : "Image"),
175
- react_1.default.createElement(ui_1.Text, { className: "text-ui-fg-subtle" }, brand.name)),
176
- react_1.default.createElement(ui_1.Button, { variant: "secondary", size: "small", onClick: onClose },
177
- react_1.default.createElement(icons_1.X, null))),
178
- error && (react_1.default.createElement(ui_1.Alert, { variant: "error", dismissible: true, className: "mb-4" }, error)),
179
- react_1.default.createElement("div", { className: "space-y-4" },
180
- imageToDisplay ? (react_1.default.createElement("div", { className: "space-y-4" },
181
- react_1.default.createElement("div", { className: "relative overflow-hidden rounded-lg border border-ui-border-base bg-ui-bg-subtle" },
182
- react_1.default.createElement("img", { src: imageToDisplay, alt: `Brand ${imageType}`, className: (0, ui_1.clx)("w-full object-contain", isLogo ? "h-32" : "h-64") }),
183
- isUploading && (react_1.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-black/50" },
184
- react_1.default.createElement("div", { className: "text-white" }, "Uploading...")))),
185
- react_1.default.createElement("div", { className: "flex gap-2" },
186
- react_1.default.createElement(ui_1.Button, { variant: "secondary", disabled: isUploading, onClick: () => document.getElementById(`${imageType}-file-input`)?.click() },
187
- react_1.default.createElement(icons_1.CloudArrowUp, { className: "mr-2" }),
188
- "Replace"),
189
- react_1.default.createElement(ui_1.Button, { variant: "danger", disabled: isUploading, onClick: handleDelete },
190
- react_1.default.createElement(icons_1.Trash, { className: "mr-2" }),
191
- "Delete")))) : (react_1.default.createElement("div", { className: (0, ui_1.clx)("flex flex-col items-center justify-center rounded-lg border-2 border-dashed transition-colors", isLogo ? "h-48" : "h-64", isDragging
192
- ? "border-ui-border-interactive bg-ui-bg-highlight"
193
- : "border-ui-border-base bg-ui-bg-subtle", !isUploading && "cursor-pointer"), onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, onClick: () => !isUploading && document.getElementById(`${imageType}-file-input`)?.click() },
194
- isLogo ? (react_1.default.createElement(icons_1.BuildingStorefront, { className: "mb-4 h-12 w-12 text-ui-fg-subtle" })) : (react_1.default.createElement(icons_1.PhotoSolid, { className: "mb-4 h-12 w-12 text-ui-fg-subtle" })),
195
- react_1.default.createElement(ui_1.Text, { className: "mb-2 text-lg font-medium" }, isDragging ? `Drop ${imageType} here` : `Upload ${isLogo ? "Logo" : "Image"}`),
196
- react_1.default.createElement(ui_1.Text, { className: "mb-4 text-center text-ui-fg-subtle" }, "Drag and drop an image here, or click to select"),
197
- react_1.default.createElement(ui_1.Text, { className: "text-sm text-ui-fg-subtle" },
198
- formatFileTypes(),
199
- " \u2022 Max ",
200
- maxSize,
201
- "MB"),
202
- isLogo && (react_1.default.createElement(ui_1.Text, { className: "mt-2 text-xs text-ui-fg-subtle" }, "Recommended: Square image, minimum 200x200px")),
203
- isUploading && (react_1.default.createElement("div", { className: "mt-4" },
204
- react_1.default.createElement(ui_1.Text, null, "Uploading..."))))),
205
- react_1.default.createElement("input", { id: `${imageType}-file-input`, type: "file", accept: allowedTypes.join(","), onChange: (e) => {
206
- const file = e.target.files?.[0];
207
- if (file)
208
- handleFileUpload(file);
209
- e.target.value = ""; // Reset input
210
- }, className: "hidden" })),
211
- react_1.default.createElement("div", { className: "mt-6 flex items-center justify-between border-t pt-4" },
212
- react_1.default.createElement(ui_1.Text, { className: "text-sm text-ui-fg-subtle" }, isLogo
213
- ? "Logo will be displayed in brand lists and product pages"
214
- : "Image can be used for brand pages and marketing"),
215
- react_1.default.createElement(ui_1.Button, { variant: "secondary", onClick: onClose }, "Close")))));
216
- };
217
- exports.BrandImageUploader = BrandImageUploader;
@@ -1 +0,0 @@
1
- export declare const sdk: any;
@@ -1,14 +0,0 @@
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.sdk = void 0;
7
- const js_sdk_1 = __importDefault(require("@medusajs/js-sdk"));
8
- exports.sdk = new js_sdk_1.default({
9
- baseUrl: import.meta.env.VITE_BACKEND_URL || "/",
10
- debug: import.meta.env.DEV,
11
- auth: {
12
- type: "session",
13
- },
14
- });
@@ -1,4 +0,0 @@
1
- import React from "react";
2
- declare const BrandsPage: () => React.JSX.Element;
3
- export declare const config: import("@medusajs/admin-sdk").RouteConfig;
4
- export default BrandsPage;