medusa-contact-us 0.0.11 → 0.0.17

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 (39) hide show
  1. package/.medusa/server/src/admin/index.js +4 -494
  2. package/.medusa/server/src/admin/index.mjs +6 -496
  3. package/.medusa/server/src/api/admin/contact-email-subscriptions/route.js +3 -3
  4. package/.medusa/server/src/api/store/contact-email-subscriptions/route.js +3 -3
  5. package/.medusa/server/src/api/store/contact-email-subscriptions/validators.js +2 -2
  6. package/.medusa/server/src/constants.js +10 -4
  7. package/.medusa/server/src/helpers/contact-subscription.js +15 -4
  8. package/.medusa/server/src/helpers/index.js +2 -4
  9. package/.medusa/server/src/index.js +8 -13
  10. package/.medusa/server/src/modules/contact-subscriptions/index.js +4 -5
  11. package/.medusa/server/src/modules/contact-subscriptions/service.js +20 -12
  12. package/.medusa/server/src/types.js +1 -208
  13. package/README.md +34 -287
  14. package/package.json +2 -3
  15. package/.medusa/server/src/api/admin/contact-requests/[id]/comments/route.js +0 -22
  16. package/.medusa/server/src/api/admin/contact-requests/[id]/route.js +0 -41
  17. package/.medusa/server/src/api/admin/contact-requests/route.js +0 -31
  18. package/.medusa/server/src/api/admin/contact-requests/validators.js +0 -19
  19. package/.medusa/server/src/api/admin/plugin/route.js +0 -11
  20. package/.medusa/server/src/api/store/contact-requests/route.js +0 -29
  21. package/.medusa/server/src/api/store/contact-requests/validators.js +0 -15
  22. package/.medusa/server/src/api/store/plugin/route.js +0 -11
  23. package/.medusa/server/src/helpers/__tests__/submit-contact-request.test.js +0 -125
  24. package/.medusa/server/src/helpers/submit-contact-request.js +0 -45
  25. package/.medusa/server/src/modules/contact-requests/index.js +0 -15
  26. package/.medusa/server/src/modules/contact-requests/migrations/Migration20241124090000.js +0 -51
  27. package/.medusa/server/src/modules/contact-requests/models/contact-request-comment.js +0 -11
  28. package/.medusa/server/src/modules/contact-requests/models/contact-request.js +0 -14
  29. package/.medusa/server/src/modules/contact-requests/service.js +0 -186
  30. package/.medusa/server/src/plugin-options.js +0 -16
  31. package/.medusa/server/src/types/__tests__/contact-options.test.js +0 -83
  32. package/.medusa/server/src/utils/__tests__/payload-validator.test.js +0 -81
  33. package/.medusa/server/src/utils/payload.js +0 -127
  34. package/.medusa/server/src/workflows/create-contact-request.js +0 -30
  35. package/.medusa/server/src/workflows/index.js +0 -8
  36. package/.medusa/server/src/workflows/steps/create-contact-request-step.js +0 -17
  37. package/.medusa/server/src/workflows/steps/send-contact-notification-step.js +0 -48
  38. package/.medusa/server/src/workflows/steps/update-contact-request-status-step.js +0 -17
  39. package/.medusa/server/src/workflows/update-contact-request-status.js +0 -32
package/README.md CHANGED
@@ -1,17 +1,13 @@
1
- <h1 align="center">Medusa Contact Us Plugin</h1>
1
+ <h1 align="center">Medusa Contact Email Subscriptions Plugin</h1>
2
2
 
3
- Collect, triage, and resolve storefront “contact us” submissions inside the Medusa Admin. The plugin ships a full stack experience: configurable form schema, database-backed requests/comments, workflows with notification hooks, open store endpoint, admin APIs, helper utilities, and a polished admin UI.
3
+ Manage storefront email subscriptions (opt-ins and opt-outs) inside the Medusa Admin. The plugin provides a complete solution: database-backed subscriptions, admin APIs, helper utilities, and a polished admin UI.
4
4
 
5
5
  ## Features
6
6
 
7
- - ✅ Configurable form schema (required email + arbitrary fields validated from plugin options)
8
- - 🧩 Status lifecycle definition (initial/intermediate/final, allowed transitions, metadata)
9
- - ✉️ Workflow-powered notifications on submission and on final status (re-uses Medusa notification module)
10
- - 🗒️ Admin-only comment trail per request with rich status history
11
- - 🖥️ React Admin extension with list + detail views, filters, status change controls, and comment composer
12
- - 🔌 Frontend helper (`submitContactRequest`) to abstract API wiring
13
7
  - ✉️ Storefront opt-in helper + admin list for email subscriptions (subscribed/unsubscribed)
14
- - 🧪 Table-driven tests for payload validation and helper logic
8
+ - 🖥️ React Admin extension with list view, filters, and search
9
+ - 🔌 Frontend helper (`upsertContactSubscription`) to abstract API wiring
10
+ - 🧪 Table-driven tests for helper logic
15
11
 
16
12
  ## Installation
17
13
 
@@ -23,160 +19,22 @@ npm install medusa-contact-us
23
19
 
24
20
  ## Configuration
25
21
 
26
- Inside `medusa-config.ts` register the plugin and tailor the options:
22
+ Inside `medusa-config.ts` register the plugin:
27
23
 
28
24
  ```ts
29
25
  import type { ConfigModule } from "@medusajs/framework/types"
30
26
  import {
31
- defineContactUsPluginOptions,
32
- ContactRequestModule,
33
27
  ContactSubscriptionModule,
34
28
  } from "medusa-contact-us"
35
29
 
36
30
  const plugins = [
37
31
  {
38
32
  resolve: "medusa-contact-us",
39
- options: defineContactUsPluginOptions({
40
- // Form configuration
41
- form: {
42
- // Maximum payload size in KB
43
- max_payload_kb: 128,
44
- // Additional custom fields beyond the required email field
45
- additional_fields: [
46
- {
47
- key: "subject",
48
- label: "Subject",
49
- description: "Brief description of your inquiry",
50
- type: "text",
51
- required: true,
52
- placeholder: "e.g., Order inquiry",
53
- helper_text: "Please provide a clear subject line",
54
- },
55
- {
56
- key: "message",
57
- label: "Message",
58
- description: "Detailed message about your inquiry",
59
- type: "textarea",
60
- required: true,
61
- placeholder: "Please describe your issue or question...",
62
- },
63
- {
64
- key: "priority",
65
- label: "Priority",
66
- description: "How urgent is your request?",
67
- type: "select",
68
- required: false,
69
- options: [
70
- { value: "low", label: "Low" },
71
- { value: "medium", label: "Medium" },
72
- { value: "high", label: "High" },
73
- { value: "urgent", label: "Urgent" },
74
- ],
75
- },
76
- {
77
- key: "order_number",
78
- label: "Order Number",
79
- description: "If this relates to an order, please provide the order number",
80
- type: "text",
81
- required: false,
82
- placeholder: "order_123456",
83
- },
84
- {
85
- key: "phone",
86
- label: "Phone Number",
87
- type: "text",
88
- required: false,
89
- placeholder: "+1 (555) 123-4567",
90
- },
91
- {
92
- key: "preferred_contact_method",
93
- label: "Preferred Contact Method",
94
- type: "select",
95
- required: false,
96
- options: [
97
- { value: "email", label: "Email" },
98
- { value: "phone", label: "Phone" },
99
- ],
100
- },
101
- {
102
- key: "is_return_request",
103
- label: "Is this a return request?",
104
- type: "boolean",
105
- required: false,
106
- },
107
- ],
108
- },
109
- // Status lifecycle configuration
110
- statuses: {
111
- // Initial status when a request is created
112
- initial: "new",
113
- // Intermediate statuses (work in progress)
114
- intermediates: ["in_review", "waiting_for_customer"],
115
- // Final status (request is complete)
116
- final: "closed",
117
- // Allowed status transitions
118
- transitions: {
119
- new: ["in_review", "closed"],
120
- in_review: ["waiting_for_customer", "closed"],
121
- waiting_for_customer: ["in_review", "closed"],
122
- },
123
- },
124
- // Status options with labels and notification settings
125
- status_options: [
126
- {
127
- code: "new",
128
- label: "New",
129
- description: "Recently submitted requests awaiting review",
130
- notify_customer: true,
131
- template: "emails/contact-received.mjml",
132
- },
133
- {
134
- code: "in_review",
135
- label: "In Review",
136
- description: "Assigned to an agent and being reviewed",
137
- notify_customer: false,
138
- },
139
- {
140
- code: "waiting_for_customer",
141
- label: "Waiting for Customer",
142
- description: "Awaiting response from customer",
143
- notify_customer: true,
144
- template: "emails/contact-waiting.mjml",
145
- },
146
- {
147
- code: "closed",
148
- label: "Closed",
149
- description: "Resolved and completed",
150
- notify_customer: true,
151
- template: "emails/contact-final.mjml",
152
- },
153
- ],
154
- // Notification configuration
155
- notifications: {
156
- // Send email when a contact request is created
157
- send_on_create: true,
158
- // Template for acknowledgement email
159
- acknowledgement_template: "emails/contact-received.mjml",
160
- // Send email when request reaches final status
161
- send_on_final_status: true,
162
- // Optional: Custom from address
163
- from_address: "support@yourstore.com",
164
- // Optional: Reply-to address
165
- reply_to: "support@yourstore.com",
166
- },
167
- // Comments configuration
168
- comments: {
169
- // Enable admin comments on contact requests
170
- enabled: true,
171
- // Require a note when changing status to final
172
- require_note_on_final: true,
173
- },
174
- }),
175
33
  },
176
34
  ]
177
35
 
178
- // Register the ContactRequestModule
179
- const modules = [ContactRequestModule, ContactSubscriptionModule]
36
+ // Register the ContactSubscriptionModule
37
+ const modules = [ContactSubscriptionModule]
180
38
 
181
39
  export default {
182
40
  projectConfig: {
@@ -189,54 +47,10 @@ export default {
189
47
  } satisfies ConfigModule
190
48
  ```
191
49
 
192
- ### Field Types
193
-
194
- Available field types for `additional_fields`:
195
- - `text`: Single-line text input
196
- - `textarea`: Multi-line text input
197
- - `number`: Numeric input
198
- - `select`: Dropdown selection (requires `options` array)
199
- - `multi_select`: Multiple selection (requires `options` array)
200
- - `boolean`: Checkbox
201
- - `date`: Date picker
202
-
203
- ### Status lifecycle best practices
204
-
205
- - Define unique status codes (kebab or snake case) and map them in `status_options`.
206
- - Provide at least one intermediate state when multiple review steps exist.
207
- - Set `notify_customer` to `true` for statuses that should trigger emails.
208
- - Configure `transitions` if you need granular control; otherwise the default is `(all non-final statuses) -> intermediates/final`.
209
-
210
50
  ## REST API
211
51
 
212
52
  ### Storefront (open)
213
53
 
214
- ```bash
215
- curl -X POST https://your-medusa.com/store/contact-requests \
216
- -H "Content-Type: application/json" \
217
- -d '{
218
- "email": "customer@example.com",
219
- "payload": { "subject": "Need help", "priority": "high" },
220
- "metadata": { "order_id": "order_123" }
221
- }'
222
- ```
223
-
224
- Response:
225
-
226
- ```json
227
- {
228
- "contact_request": {
229
- "id": "crq_123",
230
- "email": "customer@example.com",
231
- "status": "new",
232
- "payload": { "subject": "Need help", "priority": "high" },
233
- "status_history": [
234
- { "status": "new", "updated_at": "2024-11-24T10:00:00.000Z" }
235
- ]
236
- }
237
- }
238
- ```
239
-
240
54
  #### Email subscriptions
241
55
 
242
56
  ```bash
@@ -271,62 +85,40 @@ Response:
271
85
 
272
86
  ### Admin (requires admin auth cookie/token)
273
87
 
274
- List:
88
+ List subscriptions:
275
89
 
276
90
  ```bash
277
- curl -X GET "https://your-medusa.com/admin/contact-requests?status=new&limit=20" \
91
+ curl -X GET "https://your-medusa.com/admin/contact-email-subscriptions?status=subscribed&limit=20" \
278
92
  -H "Authorization: Bearer <token>"
279
93
  ```
280
94
 
281
- Detail:
282
-
283
- ```bash
284
- curl -X GET https://your-medusa.com/admin/contact-requests/crq_123 \
285
- -H "Authorization: Bearer <token>"
286
- ```
287
-
288
- Update status:
289
-
290
- ```bash
291
- curl -X PATCH https://your-medusa.com/admin/contact-requests/crq_123 \
292
- -H "Authorization: Bearer <token>" \
293
- -H "Content-Type: application/json" \
294
- -d '{ "status": "closed", "note": "Resolved via refund" }'
295
- ```
296
-
297
- Add comment:
298
-
299
- ```bash
300
- curl -X POST https://your-medusa.com/admin/contact-requests/crq_123/comments \
301
- -H "Authorization: Bearer <token>" \
302
- -H "Content-Type: application/json" \
303
- -d '{ "comment": "Waiting on supplier" }'
304
- ```
95
+ Query parameters:
96
+ - `status` – optional, filter by `subscribed` or `unsubscribed`
97
+ - `q` – optional, search by email
98
+ - `limit` optional, number of results (default: 20)
99
+ - `offset` optional, pagination offset
305
100
 
306
101
  ## Admin UI
307
102
 
308
- After running `medusa admin dev --plugins medusa-contact-us`, the sidebar will include **Contact Requests**:
309
-
310
- - **List view** – search by email, filter by status, inspect creation dates, open details with a single click.
311
- - **Detail view** – see submitted fields, live status badge, change status (with optional notes), inspect the full history timeline, and append internal comments.
312
- - **Comments** – only admins can add comments. Comments are persisted and shown newest first.
313
- - **Contact email list** – dedicated table that displays every storefront opt-in, highlights unsubscribes, and supports filtering/searching by status or email.
103
+ After running `medusa admin dev --plugins medusa-contact-us`, the sidebar will include **Contact email list**:
314
104
 
315
- All UI components follow the Medusa UI kit spacing (8pt grid), color, and accessibility guidelines.
105
+ - **List view** search by email, filter by status (subscribed/unsubscribed), inspect creation dates and unsubscribe timestamps.
106
+ - All UI components follow the Medusa UI kit spacing (8pt grid), color, and accessibility guidelines.
316
107
 
317
108
  ## Frontend helper
318
109
 
319
110
  Skip hand-writing `fetch` calls by importing the provided helpers. **Storefront requests must include a publishable API key** (create one under `Settings → API Keys` in the Medusa admin). The helpers automatically attach the header for you.
320
111
 
321
- ### Contact requests
112
+ ### Email subscriptions
322
113
 
323
114
  ```ts
324
- import { submitContactRequest } from "medusa-contact-us"
115
+ import { upsertContactSubscription } from "medusa-contact-us"
325
116
 
326
- await submitContactRequest(
117
+ await upsertContactSubscription(
327
118
  {
328
- email: "customer@example.com",
329
- payload: { subject: "Question", priority: "high" },
119
+ email: "newsletter@example.com",
120
+ status: "subscribed",
121
+ metadata: { channel: "footer" },
330
122
  },
331
123
  {
332
124
  baseUrl: "https://store.myshop.com",
@@ -339,17 +131,17 @@ Using a Medusa JS client keeps credentials in one place while still letting you
339
131
 
340
132
  ```ts
341
133
  import Medusa from "@medusajs/medusa-js"
342
- import { submitContactRequest } from "medusa-contact-us"
134
+ import { upsertContactSubscription } from "medusa-contact-us"
343
135
 
344
136
  const medusa = new Medusa({
345
137
  baseUrl: "https://store.myshop.com",
346
138
  publishableKey: "pk_live_client",
347
139
  })
348
140
 
349
- await submitContactRequest(
141
+ await upsertContactSubscription(
350
142
  {
351
- email: "customer@example.com",
352
- payload: { subject: "Returns" },
143
+ email: "newsletter@example.com",
144
+ status: "subscribed",
353
145
  },
354
146
  {
355
147
  client: medusa,
@@ -364,59 +156,22 @@ await submitContactRequest(
364
156
  For SSR or edge runtimes, preconfigure the helper once:
365
157
 
366
158
  ```ts
367
- import { createSubmitContactRequest } from "medusa-contact-us"
159
+ import { createUpsertContactSubscription } from "medusa-contact-us"
368
160
 
369
- const submitContactRequest = createSubmitContactRequest({
161
+ export const upsertSubscription = createUpsertContactSubscription({
370
162
  baseUrl: process.env.NEXT_PUBLIC_MEDUSA_URL,
371
163
  publishableApiKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
372
164
  })
373
165
 
374
166
  export async function action(formData: FormData) {
375
- await submitContactRequest({
167
+ await upsertSubscription({
376
168
  email: formData.get("email") as string,
377
- payload: {
378
- subject: formData.get("subject"),
379
- message: formData.get("message"),
380
- },
169
+ status: input.unsubscribe ? "unsubscribed" : "subscribed",
170
+ source: input.source ?? "footer_form",
381
171
  })
382
172
  }
383
173
  ```
384
174
 
385
- ### Email subscriptions
386
-
387
- ```ts
388
- import { upsertContactSubscription } from "medusa-contact-us"
389
-
390
- await upsertContactSubscription(
391
- {
392
- email: "newsletter@example.com",
393
- status: "subscribed",
394
- metadata: { channel: "footer" },
395
- },
396
- {
397
- baseUrl: "https://store.myshop.com",
398
- publishableApiKey: "pk_test_storefront",
399
- }
400
- )
401
- ```
402
-
403
- To keep deploys DRY, build a preconfigured helper and reuse it everywhere:
404
-
405
- ```ts
406
- import { createUpsertContactSubscription } from "medusa-contact-us"
407
-
408
- export const upsertSubscription = createUpsertContactSubscription({
409
- baseUrl: process.env.NEXT_PUBLIC_MEDUSA_URL,
410
- publishableApiKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
411
- })
412
-
413
- await upsertSubscription({
414
- email: input.email,
415
- status: input.unsubscribe ? "unsubscribed" : "subscribed",
416
- source: input.source ?? "footer_form",
417
- })
418
- ```
419
-
420
175
  ### Shared helper options
421
176
 
422
177
  - `publishableApiKey` – Automatically sets the `x-publishable-api-key` header when no Medusa client is used.
@@ -425,13 +180,7 @@ await upsertSubscription({
425
180
  - `fetchImpl` – Custom fetch implementation (SSR, React Native, etc.).
426
181
  - `headers` – Additional headers merged into the request (e.g., session cookie, localization). Values you pass here override the defaults, including the publishable key header if you need a per-request key.
427
182
 
428
- Customer-authenticated endpoints (like submitting a request from a logged-in area) still require the appropriate session cookie or JWT. Provide those via the `headers` option if theyre not already managed by the browser fetch call.
429
-
430
- ## Workflows & notifications
431
-
432
- - `createContactRequestWorkflow` validates payloads, persists the request, and optionally fires an acknowledgement email.
433
- - `updateContactRequestStatusWorkflow` enforces transitions, records history entries, and emits final-status notifications.
434
- - Notifications rely on the standard Medusa notification module. Ensure at least one email provider is configured; otherwise the workflows raise an error to surface misconfiguration early.
183
+ Customer-authenticated endpoints still require the appropriate session cookie or JWT. Provide those via the `headers` option if they're not already managed by the browser fetch call.
435
184
 
436
185
  ## Testing & build
437
186
 
@@ -444,6 +193,4 @@ Always run `yarn build` after development to ensure the bundler succeeds before
444
193
 
445
194
  ## Troubleshooting
446
195
 
447
- - Submit endpoint returning `422`: ensure every field defined in `form.additional_fields` is provided and matches its type.
448
- - Notifications not sent: confirm `notifications.send_on_*` flags and that the notification module is registered (the workflows throw an actionable error otherwise).
449
196
  - Admin UI blank: rebuild the plugin (`yarn build`) and restart the Admin app with the plugin registered in `medusa-config.ts`.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "medusa-contact-us",
3
- "version": "0.0.11",
4
- "description": "A starter for Medusa plugins.",
3
+ "version": "0.0.17",
4
+ "description": "Manage storefront email subscriptions (opt-ins and opt-outs) in Medusa Admin.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",
7
7
  "files": [
@@ -9,7 +9,6 @@
9
9
  ],
10
10
  "exports": {
11
11
  "./package.json": "./package.json",
12
- "./workflows": "./.medusa/server/src/workflows/index.js",
13
12
  "./helpers": "./.medusa/server/src/helpers/index.js",
14
13
  "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
15
14
  "./modules/*": "./.medusa/server/src/modules/*/index.js",
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.POST = void 0;
4
- const constants_1 = require("../../../../../constants");
5
- const validators_1 = require("../../validators");
6
- const POST = async (req, res) => {
7
- const body = validators_1.AdminAddCommentSchema.parse(req.body ?? {});
8
- const service = req.scope.resolve(constants_1.CONTACT_REQUEST_MODULE);
9
- const actorId = req.auth_context?.actor_id ||
10
- req.auth_context?.user_id ||
11
- "admin";
12
- const comment = await service.addComment({
13
- request_id: req.params.id,
14
- comment: body.comment,
15
- actor_id: actorId,
16
- });
17
- res.status(201).json({
18
- comment,
19
- });
20
- };
21
- exports.POST = POST;
22
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2NvbnRhY3QtcmVxdWVzdHMvW2lkXS9jb21tZW50cy9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx3REFBaUU7QUFFakUsaURBQXdEO0FBRWpELE1BQU0sSUFBSSxHQUFHLEtBQUssRUFBRSxHQUFrQixFQUFFLEdBQW1CLEVBQUUsRUFBRTtJQUNwRSxNQUFNLElBQUksR0FBRyxrQ0FBcUIsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUN4RCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDL0Isa0NBQXNCLENBQ3ZCLENBQUE7SUFDRCxNQUFNLE9BQU8sR0FDVixHQUFXLENBQUMsWUFBWSxFQUFFLFFBQVE7UUFDbEMsR0FBVyxDQUFDLFlBQVksRUFBRSxPQUFPO1FBQ2xDLE9BQU8sQ0FBQTtJQUVULE1BQU0sT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQztRQUN2QyxVQUFVLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1FBQ3pCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztRQUNyQixRQUFRLEVBQUUsT0FBTztLQUNsQixDQUFDLENBQUE7SUFFRixHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNuQixPQUFPO0tBQ1IsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBbkJZLFFBQUEsSUFBSSxRQW1CaEIifQ==
@@ -1,41 +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.PATCH = exports.GET = void 0;
7
- const constants_1 = require("../../../../constants");
8
- const update_contact_request_status_1 = __importDefault(require("../../../../workflows/update-contact-request-status"));
9
- const validators_1 = require("../validators");
10
- const GET = async (req, res) => {
11
- const service = req.scope.resolve(constants_1.CONTACT_REQUEST_MODULE);
12
- const { request, comments } = await service.retrieveWithComments(req.params.id);
13
- res.status(200).json({
14
- contact_request: request,
15
- comments,
16
- statuses: service.getStatusOptions(),
17
- transitions: service.getNextStatuses(request.status),
18
- });
19
- };
20
- exports.GET = GET;
21
- const PATCH = async (req, res) => {
22
- const body = validators_1.AdminUpdateContactStatusSchema.parse(req.body ?? {});
23
- const actorId = req.auth_context?.actor_id ||
24
- req.auth_context?.user_id ||
25
- "admin";
26
- const { result } = await (0, update_contact_request_status_1.default)(req.scope).run({
27
- input: {
28
- request_id: req.params.id,
29
- status: body.status,
30
- note: body.note,
31
- actor_id: actorId,
32
- },
33
- });
34
- const service = req.scope.resolve(constants_1.CONTACT_REQUEST_MODULE);
35
- res.status(200).json({
36
- contact_request: result.request,
37
- transitions: service.getNextStatuses(result.request.status),
38
- });
39
- };
40
- exports.PATCH = PATCH;
41
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2NvbnRhY3QtcmVxdWVzdHMvW2lkXS9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxxREFBOEQ7QUFFOUQsd0hBQW9HO0FBQ3BHLDhDQUE4RDtBQUV2RCxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDbkUsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQy9CLGtDQUFzQixDQUN2QixDQUFBO0lBQ0QsTUFBTSxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxvQkFBb0IsQ0FDOUQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQ2QsQ0FBQTtJQUVELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ25CLGVBQWUsRUFBRSxPQUFPO1FBQ3hCLFFBQVE7UUFDUixRQUFRLEVBQUUsT0FBTyxDQUFDLGdCQUFnQixFQUFFO1FBQ3BDLFdBQVcsRUFBRSxPQUFPLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7S0FDckQsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBZFksUUFBQSxHQUFHLE9BY2Y7QUFFTSxNQUFNLEtBQUssR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDckUsTUFBTSxJQUFJLEdBQUcsMkNBQThCLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUE7SUFDakUsTUFBTSxPQUFPLEdBQ1YsR0FBVyxDQUFDLFlBQVksRUFBRSxRQUFRO1FBQ2xDLEdBQVcsQ0FBQyxZQUFZLEVBQUUsT0FBTztRQUNsQyxPQUFPLENBQUE7SUFFVCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLHVDQUFrQyxFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7UUFDekUsS0FBSyxFQUFFO1lBQ0wsVUFBVSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUN6QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO1lBQ2YsUUFBUSxFQUFFLE9BQU87U0FDbEI7S0FDRixDQUFDLENBQUE7SUFFRixNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDL0Isa0NBQXNCLENBQ3ZCLENBQUE7SUFFRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNuQixlQUFlLEVBQUUsTUFBTSxDQUFDLE9BQU87UUFDL0IsV0FBVyxFQUFFLE9BQU8sQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7S0FDNUQsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBeEJZLFFBQUEsS0FBSyxTQXdCakIifQ==
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GET = void 0;
4
- const constants_1 = require("../../../constants");
5
- const validators_1 = require("./validators");
6
- const GET = async (req, res) => {
7
- const query = validators_1.AdminListContactRequestsSchema.parse(req.query ?? {});
8
- const service = req.scope.resolve(constants_1.CONTACT_REQUEST_MODULE);
9
- const selector = {};
10
- if (query.status) {
11
- selector.status = query.status;
12
- }
13
- if (query.email || query.q) {
14
- const email = (query.email ?? query.q).toLowerCase();
15
- selector.email = email;
16
- }
17
- const [contactRequests, count] = await service.listWithFilters(selector, {
18
- take: query.limit,
19
- skip: query.offset,
20
- order: { created_at: "DESC" },
21
- });
22
- res.status(200).json({
23
- contact_requests: contactRequests,
24
- count,
25
- offset: query.offset,
26
- limit: query.limit,
27
- statuses: service.getStatusOptions(),
28
- });
29
- };
30
- exports.GET = GET;
31
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2NvbnRhY3QtcmVxdWVzdHMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0Esa0RBQTJEO0FBRTNELDZDQUE2RDtBQUV0RCxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDbkUsTUFBTSxLQUFLLEdBQUcsMkNBQThCLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUE7SUFDbkUsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQy9CLGtDQUFzQixDQUN2QixDQUFBO0lBRUQsTUFBTSxRQUFRLEdBQTRCLEVBQUUsQ0FBQTtJQUU1QyxJQUFJLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNqQixRQUFRLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUE7SUFDaEMsQ0FBQztJQUNELElBQUksS0FBSyxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDM0IsTUFBTSxLQUFLLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtRQUNyRCxRQUFRLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtJQUN4QixDQUFDO0lBRUQsTUFBTSxDQUFDLGVBQWUsRUFBRSxLQUFLLENBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFO1FBQ3ZFLElBQUksRUFBRSxLQUFLLENBQUMsS0FBSztRQUNqQixJQUFJLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDbEIsS0FBSyxFQUFFLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRTtLQUM5QixDQUFDLENBQUE7SUFFRixHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNuQixnQkFBZ0IsRUFBRSxlQUFlO1FBQ2pDLEtBQUs7UUFDTCxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLO1FBQ2xCLFFBQVEsRUFBRSxPQUFPLENBQUMsZ0JBQWdCLEVBQUU7S0FDckMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBN0JZLFFBQUEsR0FBRyxPQTZCZiJ9
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AdminAddCommentSchema = exports.AdminUpdateContactStatusSchema = exports.AdminListContactRequestsSchema = void 0;
4
- const zod_1 = require("zod");
5
- exports.AdminListContactRequestsSchema = zod_1.z.object({
6
- status: zod_1.z.string().optional(),
7
- email: zod_1.z.string().optional(),
8
- q: zod_1.z.string().optional(),
9
- limit: zod_1.z.coerce.number().min(1).max(100).default(20),
10
- offset: zod_1.z.coerce.number().min(0).default(0),
11
- });
12
- exports.AdminUpdateContactStatusSchema = zod_1.z.object({
13
- status: zod_1.z.string().min(1),
14
- note: zod_1.z.string().optional(),
15
- });
16
- exports.AdminAddCommentSchema = zod_1.z.object({
17
- comment: zod_1.z.string().min(2, "Comment must be at least 2 characters"),
18
- });
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYWRtaW4vY29udGFjdC1yZXF1ZXN0cy92YWxpZGF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZCQUF1QjtBQUVWLFFBQUEsOEJBQThCLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNyRCxNQUFNLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM3QixLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM1QixDQUFDLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUN4QixLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7SUFDcEQsTUFBTSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7Q0FDNUMsQ0FBQyxDQUFBO0FBTVcsUUFBQSw4QkFBOEIsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3JELE1BQU0sRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN6QixJQUFJLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtDQUM1QixDQUFDLENBQUE7QUFNVyxRQUFBLHFCQUFxQixHQUFHLE9BQUMsQ0FBQyxNQUFNLENBQUM7SUFDNUMsT0FBTyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLHVDQUF1QyxDQUFDO0NBQ3BFLENBQUMsQ0FBQSJ9
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GET = GET;
4
- const constants_1 = require("../../../constants");
5
- async function GET(req, res) {
6
- const service = req.scope.resolve(constants_1.CONTACT_REQUEST_MODULE);
7
- res.status(200).json({
8
- contact_us: service.getOptions(),
9
- });
10
- }
11
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3BsdWdpbi9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUlBLGtCQVdDO0FBZEQsa0RBQTJEO0FBR3BELEtBQUssVUFBVSxHQUFHLENBQ3ZCLEdBQWtCLEVBQ2xCLEdBQW1CO0lBRW5CLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUMvQixrQ0FBc0IsQ0FDdkIsQ0FBQTtJQUVELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ25CLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxFQUFFO0tBQ2pDLENBQUMsQ0FBQTtBQUNKLENBQUMifQ==
@@ -1,29 +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.POST = exports.AUTHENTICATE = void 0;
7
- const utils_1 = require("@medusajs/framework/utils");
8
- const create_contact_request_1 = __importDefault(require("../../../workflows/create-contact-request"));
9
- const validators_1 = require("./validators");
10
- exports.AUTHENTICATE = false;
11
- const POST = async (req, res) => {
12
- const body = validators_1.StoreCreateContactRequestSchema.parse(req.body ?? {});
13
- if (!body.email) {
14
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Email is required.");
15
- }
16
- const { result } = await (0, create_contact_request_1.default)(req.scope).run({
17
- input: {
18
- email: body.email,
19
- payload: body.payload,
20
- metadata: body.metadata,
21
- source: body.source ?? "storefront",
22
- },
23
- });
24
- res.status(201).json({
25
- contact_request: result.request,
26
- });
27
- };
28
- exports.POST = POST;
29
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2NvbnRhY3QtcmVxdWVzdHMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EscURBQXVEO0FBQ3ZELHVHQUFvRjtBQUNwRiw2Q0FBOEQ7QUFFakQsUUFBQSxZQUFZLEdBQUcsS0FBSyxDQUFBO0FBRTFCLE1BQU0sSUFBSSxHQUFHLEtBQUssRUFBRSxHQUFrQixFQUFFLEdBQW1CLEVBQUUsRUFBRTtJQUNwRSxNQUFNLElBQUksR0FBRyw0Q0FBK0IsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUVsRSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2hCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQzlCLG9CQUFvQixDQUNyQixDQUFBO0lBQ0gsQ0FBQztJQUVELE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLElBQUEsZ0NBQTRCLEVBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUNuRSxLQUFLLEVBQUU7WUFDTCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1lBQ3JCLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUN2QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sSUFBSSxZQUFZO1NBQ3BDO0tBQ0YsQ0FBQyxDQUFBO0lBRUYsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDbkIsZUFBZSxFQUFFLE1BQU0sQ0FBQyxPQUFPO0tBQ2hDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQTtBQXRCWSxRQUFBLElBQUksUUFzQmhCIn0=
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StoreCreateContactRequestSchema = exports.ContactRequestPayloadSchema = void 0;
4
- const zod_1 = require("zod");
5
- exports.ContactRequestPayloadSchema = zod_1.z
6
- .record(zod_1.z.any())
7
- .optional()
8
- .default({});
9
- exports.StoreCreateContactRequestSchema = zod_1.z.object({
10
- email: zod_1.z.string().email(),
11
- payload: exports.ContactRequestPayloadSchema,
12
- metadata: zod_1.z.record(zod_1.z.any()).optional(),
13
- source: zod_1.z.string().optional(),
14
- });
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvc3RvcmUvY29udGFjdC1yZXF1ZXN0cy92YWxpZGF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZCQUF1QjtBQUVWLFFBQUEsMkJBQTJCLEdBQUcsT0FBQztLQUN6QyxNQUFNLENBQUMsT0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO0tBQ2YsUUFBUSxFQUFFO0tBQ1YsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBRUQsUUFBQSwrQkFBK0IsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQ3RELEtBQUssRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFO0lBQ3pCLE9BQU8sRUFBRSxtQ0FBMkI7SUFDcEMsUUFBUSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUMsT0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFO0lBQ3RDLE1BQU0sRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQzlCLENBQUMsQ0FBQSJ9
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GET = GET;
4
- const constants_1 = require("../../../constants");
5
- async function GET(req, res) {
6
- const service = req.scope.resolve(constants_1.CONTACT_REQUEST_MODULE);
7
- res.status(200).json({
8
- contact_us: service.getOptions(),
9
- });
10
- }
11
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3BsdWdpbi9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUlBLGtCQVdDO0FBZEQsa0RBQTJEO0FBR3BELEtBQUssVUFBVSxHQUFHLENBQ3ZCLEdBQWtCLEVBQ2xCLEdBQW1CO0lBRW5CLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUMvQixrQ0FBc0IsQ0FDdkIsQ0FBQTtJQUVELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ25CLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxFQUFFO0tBQ2pDLENBQUMsQ0FBQTtBQUNKLENBQUMifQ==