medusa-contact-us 0.0.2 → 0.0.8

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 (23) hide show
  1. package/.medusa/server/src/admin/index.js +176 -1
  2. package/.medusa/server/src/admin/index.mjs +176 -1
  3. package/.medusa/server/src/api/admin/contact-email-subscriptions/route.js +29 -0
  4. package/.medusa/server/src/api/admin/contact-email-subscriptions/validators.js +12 -0
  5. package/.medusa/server/src/api/store/contact-email-subscriptions/route.js +19 -0
  6. package/.medusa/server/src/api/store/contact-email-subscriptions/validators.js +15 -0
  7. package/.medusa/server/src/constants.js +3 -2
  8. package/.medusa/server/src/helpers/__tests__/contact-subscription.test.js +109 -0
  9. package/.medusa/server/src/helpers/__tests__/submit-contact-request.test.js +33 -1
  10. package/.medusa/server/src/helpers/base-client.js +36 -0
  11. package/.medusa/server/src/helpers/contact-subscription.js +45 -0
  12. package/.medusa/server/src/helpers/index.js +5 -2
  13. package/.medusa/server/src/helpers/submit-contact-request.js +8 -29
  14. package/.medusa/server/src/index.js +7 -2
  15. package/.medusa/server/src/modules/contact-requests/migrations/Migration20241124090000.js +7 -2
  16. package/.medusa/server/src/modules/contact-requests/models/contact-request-comment.js +1 -2
  17. package/.medusa/server/src/modules/contact-requests/models/contact-request.js +1 -3
  18. package/.medusa/server/src/modules/contact-subscriptions/index.js +15 -0
  19. package/.medusa/server/src/modules/contact-subscriptions/migrations/Migration20241126103000.js +38 -0
  20. package/.medusa/server/src/modules/contact-subscriptions/models/contact-email-subscription.js +13 -0
  21. package/.medusa/server/src/modules/contact-subscriptions/service.js +57 -0
  22. package/README.md +132 -12
  23. package/package.json +2 -1
package/README.md CHANGED
@@ -10,6 +10,7 @@ Collect, triage, and resolve storefront “contact us” submissions inside the
10
10
  - 🗒️ Admin-only comment trail per request with rich status history
11
11
  - 🖥️ React Admin extension with list + detail views, filters, status change controls, and comment composer
12
12
  - 🔌 Frontend helper (`submitContactRequest`) to abstract API wiring
13
+ - ✉️ Storefront opt-in helper + admin list for email subscriptions (subscribed/unsubscribed)
13
14
  - 🧪 Table-driven tests for payload validation and helper logic
14
15
 
15
16
  ## Installation
@@ -29,6 +30,7 @@ import type { ConfigModule } from "@medusajs/framework/types"
29
30
  import {
30
31
  defineContactUsPluginOptions,
31
32
  ContactRequestModule,
33
+ ContactSubscriptionModule,
32
34
  } from "medusa-contact-us"
33
35
 
34
36
  const plugins = [
@@ -174,7 +176,7 @@ const plugins = [
174
176
  ]
175
177
 
176
178
  // Register the ContactRequestModule
177
- const modules = [ContactRequestModule]
179
+ const modules = [ContactRequestModule, ContactSubscriptionModule]
178
180
 
179
181
  export default {
180
182
  projectConfig: {
@@ -235,6 +237,38 @@ Response:
235
237
  }
236
238
  ```
237
239
 
240
+ #### Email subscriptions
241
+
242
+ ```bash
243
+ curl -X POST https://your-medusa.com/store/contact-email-subscriptions \
244
+ -H "Content-Type: application/json" \
245
+ -H "x-publishable-api-key: pk_storefront" \
246
+ -d '{
247
+ "email": "newsletter@example.com",
248
+ "status": "subscribed",
249
+ "source": "footer"
250
+ }'
251
+ ```
252
+
253
+ Body fields:
254
+ - `email` – required, unique per entry (case-insensitive).
255
+ - `status` – optional, defaults to `subscribed`. Pass `"unsubscribed"` to honor opt-outs.
256
+ - `metadata` / `source` – optional context stored alongside the entry.
257
+
258
+ Response:
259
+
260
+ ```json
261
+ {
262
+ "subscription": {
263
+ "id": "csub_123",
264
+ "email": "newsletter@example.com",
265
+ "status": "subscribed",
266
+ "source": "footer",
267
+ "created_at": "2024-11-26T10:00:00.000Z"
268
+ }
269
+ }
270
+ ```
271
+
238
272
  ### Admin (requires admin auth cookie/token)
239
273
 
240
274
  List:
@@ -276,37 +310,123 @@ After running `medusa admin dev --plugins medusa-contact-us`, the sidebar will i
276
310
  - **List view** – search by email, filter by status, inspect creation dates, open details with a single click.
277
311
  - **Detail view** – see submitted fields, live status badge, change status (with optional notes), inspect the full history timeline, and append internal comments.
278
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.
279
314
 
280
315
  All UI components follow the Medusa UI kit spacing (8pt grid), color, and accessibility guidelines.
281
316
 
282
317
  ## Frontend helper
283
318
 
284
- Skip hand-writing `fetch` calls by importing the provided helper:
319
+ 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
+
321
+ ### Contact requests
285
322
 
286
323
  ```ts
287
324
  import { submitContactRequest } from "medusa-contact-us"
288
325
 
289
- await submitContactRequest({
290
- email: "customer@example.com",
291
- payload: { subject: "Question", priority: "high" },
292
- })
326
+ await submitContactRequest(
327
+ {
328
+ email: "customer@example.com",
329
+ payload: { subject: "Question", priority: "high" },
330
+ },
331
+ {
332
+ baseUrl: "https://store.myshop.com",
333
+ publishableApiKey: "pk_test_storefront",
334
+ }
335
+ )
293
336
  ```
294
337
 
295
- Passing a Medusa JS client automatically reuses its transport:
338
+ Using a Medusa JS client keeps credentials in one place while still letting you override headers (including publishable keys) per call:
296
339
 
297
340
  ```ts
298
341
  import Medusa from "@medusajs/medusa-js"
299
342
  import { submitContactRequest } from "medusa-contact-us"
300
343
 
301
- const client = new Medusa({ baseUrl: "https://your-medusa.com" })
344
+ const medusa = new Medusa({
345
+ baseUrl: "https://store.myshop.com",
346
+ publishableKey: "pk_live_client",
347
+ })
348
+
349
+ await submitContactRequest(
350
+ {
351
+ email: "customer@example.com",
352
+ payload: { subject: "Returns" },
353
+ },
354
+ {
355
+ client: medusa,
356
+ publishableApiKey: "pk_live_client",
357
+ headers: {
358
+ Cookie: "connect.sid=...",
359
+ },
360
+ }
361
+ )
362
+ ```
363
+
364
+ For SSR or edge runtimes, preconfigure the helper once:
302
365
 
303
- await submitContactRequest({
304
- client,
305
- email: "customer@example.com",
306
- payload: { subject: "Returns" },
366
+ ```ts
367
+ import { createSubmitContactRequest } from "medusa-contact-us"
368
+
369
+ const submitContactRequest = createSubmitContactRequest({
370
+ baseUrl: process.env.NEXT_PUBLIC_MEDUSA_URL,
371
+ publishableApiKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
307
372
  })
373
+
374
+ export async function action(formData: FormData) {
375
+ await submitContactRequest({
376
+ email: formData.get("email") as string,
377
+ payload: {
378
+ subject: formData.get("subject"),
379
+ message: formData.get("message"),
380
+ },
381
+ })
382
+ }
308
383
  ```
309
384
 
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
+ ### Shared helper options
421
+
422
+ - `publishableApiKey` – Automatically sets the `x-publishable-api-key` header when no Medusa client is used.
423
+ - `baseUrl` – Storefront API origin (ignored when `client` is provided).
424
+ - `client` – Pre-configured Medusa JS/SDK instance (reuses its base URL and publishable key).
425
+ - `fetchImpl` – Custom fetch implementation (SSR, React Native, etc.).
426
+ - `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
+
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 they’re not already managed by the browser fetch call.
429
+
310
430
  ## Workflows & notifications
311
431
 
312
432
  - `createContactRequestWorkflow` validates payloads, persists the request, and optionally fires an acknowledgement email.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-contact-us",
3
- "version": "0.0.2",
3
+ "version": "0.0.8",
4
4
  "description": "A starter for Medusa plugins.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",
@@ -10,6 +10,7 @@
10
10
  "exports": {
11
11
  "./package.json": "./package.json",
12
12
  "./workflows": "./.medusa/server/src/workflows/index.js",
13
+ "./helpers": "./.medusa/server/src/helpers/index.js",
13
14
  "./.medusa/server/src/modules/*": "./.medusa/server/src/modules/*/index.js",
14
15
  "./modules/*": "./.medusa/server/src/modules/*/index.js",
15
16
  "./providers/*": "./.medusa/server/src/providers/*/index.js",