medusa-contact-us 0.0.3 → 0.0.11

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 +6 -35
  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 +107 -16
  23. package/package.json +1 -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,49 +310,50 @@ 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. **Most storefront requests require a publishable API key**, which you can create in the Medusa dashboard (`Settings → API Keys`).
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
- const options = {
290
- baseUrl: "https://store.myshop.com",
291
- publishableApiKey: "pk_your_publishable_api_key_here",
292
- }
293
-
294
326
  await submitContactRequest(
295
327
  {
296
328
  email: "customer@example.com",
297
329
  payload: { subject: "Question", priority: "high" },
298
330
  },
299
- options
331
+ {
332
+ baseUrl: "https://store.myshop.com",
333
+ publishableApiKey: "pk_test_storefront",
334
+ }
300
335
  )
301
336
  ```
302
337
 
303
- Passing a Medusa JS client automatically reuses its transport and publishable key:
338
+ Using a Medusa JS client keeps credentials in one place while still letting you override headers (including publishable keys) per call:
304
339
 
305
340
  ```ts
306
341
  import Medusa from "@medusajs/medusa-js"
307
342
  import { submitContactRequest } from "medusa-contact-us"
308
343
 
309
- const client = new Medusa({
344
+ const medusa = new Medusa({
310
345
  baseUrl: "https://store.myshop.com",
311
- publishableKey: "pk_your_publishable_api_key_here",
346
+ publishableKey: "pk_live_client",
312
347
  })
313
348
 
314
349
  await submitContactRequest(
315
350
  {
316
- client,
317
351
  email: "customer@example.com",
318
352
  payload: { subject: "Returns" },
319
353
  },
320
354
  {
321
- // Additional headers (cookies/JWT) can still be provided when needed
355
+ client: medusa,
356
+ publishableApiKey: "pk_live_client",
322
357
  headers: {
323
358
  Cookie: "connect.sid=...",
324
359
  },
@@ -326,13 +361,69 @@ await submitContactRequest(
326
361
  )
327
362
  ```
328
363
 
329
- **Helper options:**
364
+ For SSR or edge runtimes, preconfigure the helper once:
365
+
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,
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
+ }
383
+ ```
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
330
421
 
331
- - `publishableApiKey` – Required for public storefront calls when not passing a Medusa JS client.
422
+ - `publishableApiKey` – Automatically sets the `x-publishable-api-key` header when no Medusa client is used.
332
423
  - `baseUrl` – Storefront API origin (ignored when `client` is provided).
333
424
  - `client` – Pre-configured Medusa JS/SDK instance (reuses its base URL and publishable key).
334
425
  - `fetchImpl` – Custom fetch implementation (SSR, React Native, etc.).
335
- - `headers` – Additional headers merged into the request (e.g., session cookie, localization).
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.
336
427
 
337
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.
338
429
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-contact-us",
3
- "version": "0.0.3",
3
+ "version": "0.0.11",
4
4
  "description": "A starter for Medusa plugins.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",