medusa-contact-us 0.0.22 → 0.0.24

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.
@@ -427,11 +427,54 @@ const ContactRequestDetailPage = () => {
427
427
  const [isAssigning, setIsAssigning] = react.useState(false);
428
428
  const [assignError, setAssignError] = react.useState(null);
429
429
  const [assignSuccess, setAssignSuccess] = react.useState(false);
430
+ const [adminUsers, setAdminUsers] = react.useState([]);
431
+ const [adminSearchQuery, setAdminSearchQuery] = react.useState("");
432
+ const [isAdminDropdownOpen, setIsAdminDropdownOpen] = react.useState(false);
433
+ const [isLoadingAdmins, setIsLoadingAdmins] = react.useState(false);
434
+ const [selectedAdminIndex, setSelectedAdminIndex] = react.useState(-1);
435
+ const adminDropdownRef = react.useRef(null);
436
+ const adminInputRef = react.useRef(null);
430
437
  const [commentText, setCommentText] = react.useState("");
431
438
  const [commentImages, setCommentImages] = react.useState([]);
432
439
  const [isCreatingComment, setIsCreatingComment] = react.useState(false);
433
440
  const [commentError, setCommentError] = react.useState(null);
434
441
  const [commentSuccess, setCommentSuccess] = react.useState(false);
442
+ const useDebounce2 = (value, delay) => {
443
+ const [debouncedValue, setDebouncedValue] = react.useState(value);
444
+ react.useEffect(() => {
445
+ const handler = setTimeout(() => setDebouncedValue(value), delay);
446
+ return () => clearTimeout(handler);
447
+ }, [value, delay]);
448
+ return debouncedValue;
449
+ };
450
+ const debouncedAdminSearch = useDebounce2(adminSearchQuery, 300);
451
+ const fetchAdminUsers = react.useCallback(async (searchQuery) => {
452
+ try {
453
+ setIsLoadingAdmins(true);
454
+ const params = new URLSearchParams();
455
+ if (searchQuery) {
456
+ params.set("q", searchQuery);
457
+ }
458
+ const response = await fetch(`/admin/users?${params.toString()}`, {
459
+ credentials: "include"
460
+ });
461
+ if (!response.ok) {
462
+ throw new Error("Unable to load admin users");
463
+ }
464
+ const payload = await response.json();
465
+ setAdminUsers(payload.users || []);
466
+ } catch (fetchError) {
467
+ console.error("Error fetching admin users:", fetchError);
468
+ setAdminUsers([]);
469
+ } finally {
470
+ setIsLoadingAdmins(false);
471
+ }
472
+ }, []);
473
+ const filteredAdmins = adminUsers.filter((admin) => {
474
+ if (!debouncedAdminSearch) return true;
475
+ const query = debouncedAdminSearch.toLowerCase();
476
+ return admin.name.toLowerCase().includes(query) || admin.email.toLowerCase().includes(query) || admin.id.toLowerCase().includes(query);
477
+ });
435
478
  react.useEffect(() => {
436
479
  if (!id) {
437
480
  navigate("/contact-requests");
@@ -454,6 +497,7 @@ const ContactRequestDetailPage = () => {
454
497
  setNextAllowedStatuses(payload.next_allowed_statuses ?? []);
455
498
  setSelectedStatus("");
456
499
  setSelectedAssignTo("");
500
+ setAdminSearchQuery("");
457
501
  } catch (loadError) {
458
502
  const message = loadError instanceof Error ? loadError.message : "Unable to load contact request";
459
503
  setError(message);
@@ -463,6 +507,59 @@ const ContactRequestDetailPage = () => {
463
507
  };
464
508
  void loadRequest();
465
509
  }, [id, navigate]);
510
+ react.useEffect(() => {
511
+ if (isAdminDropdownOpen) {
512
+ void fetchAdminUsers(debouncedAdminSearch || void 0);
513
+ }
514
+ }, [isAdminDropdownOpen, debouncedAdminSearch, fetchAdminUsers]);
515
+ react.useEffect(() => {
516
+ const handleClickOutside = (event) => {
517
+ if (adminDropdownRef.current && !adminDropdownRef.current.contains(event.target) && adminInputRef.current && !adminInputRef.current.contains(event.target)) {
518
+ setIsAdminDropdownOpen(false);
519
+ setSelectedAdminIndex(-1);
520
+ }
521
+ };
522
+ if (isAdminDropdownOpen) {
523
+ document.addEventListener("mousedown", handleClickOutside);
524
+ return () => document.removeEventListener("mousedown", handleClickOutside);
525
+ }
526
+ }, [isAdminDropdownOpen]);
527
+ const handleAdminKeyDown = (event) => {
528
+ if (event.key === "ArrowDown") {
529
+ event.preventDefault();
530
+ setSelectedAdminIndex(
531
+ (prev) => prev < filteredAdmins.length - 1 ? prev + 1 : prev
532
+ );
533
+ setIsAdminDropdownOpen(true);
534
+ } else if (event.key === "ArrowUp") {
535
+ event.preventDefault();
536
+ setSelectedAdminIndex((prev) => prev > 0 ? prev - 1 : -1);
537
+ setIsAdminDropdownOpen(true);
538
+ } else if (event.key === "Enter" && selectedAdminIndex >= 0) {
539
+ event.preventDefault();
540
+ const admin = filteredAdmins[selectedAdminIndex];
541
+ if (admin) {
542
+ handleAdminSelect(admin);
543
+ }
544
+ } else if (event.key === "Escape") {
545
+ setIsAdminDropdownOpen(false);
546
+ setSelectedAdminIndex(-1);
547
+ }
548
+ };
549
+ const handleAdminSelect = (admin) => {
550
+ setSelectedAssignTo(admin.id);
551
+ setAdminSearchQuery(admin.name || admin.email);
552
+ setIsAdminDropdownOpen(false);
553
+ setSelectedAdminIndex(-1);
554
+ };
555
+ react.useEffect(() => {
556
+ if ((request == null ? void 0 : request.assign_to) && adminUsers.length > 0) {
557
+ const assignedAdmin = adminUsers.find((admin) => admin.id === request.assign_to);
558
+ if (assignedAdmin && !adminSearchQuery) {
559
+ setAdminSearchQuery(assignedAdmin.name || assignedAdmin.email);
560
+ }
561
+ }
562
+ }, [request == null ? void 0 : request.assign_to, adminUsers, adminSearchQuery]);
466
563
  const handleStatusUpdate = async () => {
467
564
  if (!id || !selectedStatus) {
468
565
  return;
@@ -721,18 +818,67 @@ const ContactRequestDetailPage = () => {
721
818
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: request.assign_to ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "small", className: "mt-1", children: request.assign_to }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-subtle", children: "Unassigned" }) })
722
819
  ] }),
723
820
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-end", children: [
724
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
725
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "Admin User ID" }),
726
- /* @__PURE__ */ jsxRuntime.jsx(
727
- ui.Input,
728
- {
729
- type: "text",
730
- value: selectedAssignTo,
731
- onChange: (event) => setSelectedAssignTo(event.target.value),
732
- placeholder: "Enter admin user ID",
733
- className: "w-full"
734
- }
735
- )
821
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 relative", children: [
822
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "Assign To Admin" }),
823
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
824
+ /* @__PURE__ */ jsxRuntime.jsx(
825
+ ui.Input,
826
+ {
827
+ ref: adminInputRef,
828
+ type: "text",
829
+ value: adminSearchQuery,
830
+ onChange: (event) => {
831
+ setAdminSearchQuery(event.target.value);
832
+ setIsAdminDropdownOpen(true);
833
+ setSelectedAdminIndex(-1);
834
+ },
835
+ onFocus: () => {
836
+ setIsAdminDropdownOpen(true);
837
+ if (adminUsers.length === 0) {
838
+ void fetchAdminUsers();
839
+ }
840
+ },
841
+ onKeyDown: handleAdminKeyDown,
842
+ placeholder: "Search admin by name, email, or ID...",
843
+ className: "w-full"
844
+ }
845
+ ),
846
+ isAdminDropdownOpen && /* @__PURE__ */ jsxRuntime.jsx(
847
+ "div",
848
+ {
849
+ ref: adminDropdownRef,
850
+ className: "absolute z-50 mt-1 w-full max-h-60 overflow-auto rounded-md border border-ui-border-base bg-ui-bg-base shadow-lg",
851
+ children: isLoadingAdmins ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Loading admins..." }) }) : filteredAdmins.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "py-1", children: filteredAdmins.map((admin, index) => /* @__PURE__ */ jsxRuntime.jsx(
852
+ "li",
853
+ {
854
+ className: `cursor-pointer px-4 py-3 hover:bg-ui-bg-subtle-hover ${index === selectedAdminIndex ? "bg-ui-bg-subtle-hover" : ""}`,
855
+ onClick: () => handleAdminSelect(admin),
856
+ onMouseEnter: () => setSelectedAdminIndex(index),
857
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
858
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
859
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-medium", children: admin.name }),
860
+ admin.id === selectedAssignTo && /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", children: "Selected" })
861
+ ] }),
862
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: admin.email }),
863
+ /* @__PURE__ */ jsxRuntime.jsx(
864
+ ui.Text,
865
+ {
866
+ size: "xsmall",
867
+ className: "text-ui-fg-muted font-mono",
868
+ children: admin.id
869
+ }
870
+ )
871
+ ] })
872
+ },
873
+ admin.id
874
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: adminSearchQuery ? "No admins found" : "Start typing to search admins" }) })
875
+ }
876
+ )
877
+ ] }),
878
+ selectedAssignTo && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "mt-1 text-ui-fg-subtle", children: [
879
+ "Selected Admin ID: ",
880
+ selectedAssignTo
881
+ ] })
736
882
  ] }),
737
883
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
738
884
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -740,7 +886,7 @@ const ContactRequestDetailPage = () => {
740
886
  {
741
887
  variant: "primary",
742
888
  onClick: handleAssign,
743
- disabled: isAssigning,
889
+ disabled: isAssigning || !selectedAssignTo,
744
890
  isLoading: isAssigning,
745
891
  children: "Assign"
746
892
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useState, useCallback, useEffect, useMemo } from "react";
2
+ import { useState, useCallback, useEffect, useMemo, useRef } from "react";
3
3
  import { defineRouteConfig } from "@medusajs/admin-sdk";
4
4
  import { Container, Heading, Text, Button, Input, Badge, Textarea } from "@medusajs/ui";
5
5
  import { Envelope, ChatBubbleLeftRight, ArrowLeft } from "@medusajs/icons";
@@ -426,11 +426,54 @@ const ContactRequestDetailPage = () => {
426
426
  const [isAssigning, setIsAssigning] = useState(false);
427
427
  const [assignError, setAssignError] = useState(null);
428
428
  const [assignSuccess, setAssignSuccess] = useState(false);
429
+ const [adminUsers, setAdminUsers] = useState([]);
430
+ const [adminSearchQuery, setAdminSearchQuery] = useState("");
431
+ const [isAdminDropdownOpen, setIsAdminDropdownOpen] = useState(false);
432
+ const [isLoadingAdmins, setIsLoadingAdmins] = useState(false);
433
+ const [selectedAdminIndex, setSelectedAdminIndex] = useState(-1);
434
+ const adminDropdownRef = useRef(null);
435
+ const adminInputRef = useRef(null);
429
436
  const [commentText, setCommentText] = useState("");
430
437
  const [commentImages, setCommentImages] = useState([]);
431
438
  const [isCreatingComment, setIsCreatingComment] = useState(false);
432
439
  const [commentError, setCommentError] = useState(null);
433
440
  const [commentSuccess, setCommentSuccess] = useState(false);
441
+ const useDebounce2 = (value, delay) => {
442
+ const [debouncedValue, setDebouncedValue] = useState(value);
443
+ useEffect(() => {
444
+ const handler = setTimeout(() => setDebouncedValue(value), delay);
445
+ return () => clearTimeout(handler);
446
+ }, [value, delay]);
447
+ return debouncedValue;
448
+ };
449
+ const debouncedAdminSearch = useDebounce2(adminSearchQuery, 300);
450
+ const fetchAdminUsers = useCallback(async (searchQuery) => {
451
+ try {
452
+ setIsLoadingAdmins(true);
453
+ const params = new URLSearchParams();
454
+ if (searchQuery) {
455
+ params.set("q", searchQuery);
456
+ }
457
+ const response = await fetch(`/admin/users?${params.toString()}`, {
458
+ credentials: "include"
459
+ });
460
+ if (!response.ok) {
461
+ throw new Error("Unable to load admin users");
462
+ }
463
+ const payload = await response.json();
464
+ setAdminUsers(payload.users || []);
465
+ } catch (fetchError) {
466
+ console.error("Error fetching admin users:", fetchError);
467
+ setAdminUsers([]);
468
+ } finally {
469
+ setIsLoadingAdmins(false);
470
+ }
471
+ }, []);
472
+ const filteredAdmins = adminUsers.filter((admin) => {
473
+ if (!debouncedAdminSearch) return true;
474
+ const query = debouncedAdminSearch.toLowerCase();
475
+ return admin.name.toLowerCase().includes(query) || admin.email.toLowerCase().includes(query) || admin.id.toLowerCase().includes(query);
476
+ });
434
477
  useEffect(() => {
435
478
  if (!id) {
436
479
  navigate("/contact-requests");
@@ -453,6 +496,7 @@ const ContactRequestDetailPage = () => {
453
496
  setNextAllowedStatuses(payload.next_allowed_statuses ?? []);
454
497
  setSelectedStatus("");
455
498
  setSelectedAssignTo("");
499
+ setAdminSearchQuery("");
456
500
  } catch (loadError) {
457
501
  const message = loadError instanceof Error ? loadError.message : "Unable to load contact request";
458
502
  setError(message);
@@ -462,6 +506,59 @@ const ContactRequestDetailPage = () => {
462
506
  };
463
507
  void loadRequest();
464
508
  }, [id, navigate]);
509
+ useEffect(() => {
510
+ if (isAdminDropdownOpen) {
511
+ void fetchAdminUsers(debouncedAdminSearch || void 0);
512
+ }
513
+ }, [isAdminDropdownOpen, debouncedAdminSearch, fetchAdminUsers]);
514
+ useEffect(() => {
515
+ const handleClickOutside = (event) => {
516
+ if (adminDropdownRef.current && !adminDropdownRef.current.contains(event.target) && adminInputRef.current && !adminInputRef.current.contains(event.target)) {
517
+ setIsAdminDropdownOpen(false);
518
+ setSelectedAdminIndex(-1);
519
+ }
520
+ };
521
+ if (isAdminDropdownOpen) {
522
+ document.addEventListener("mousedown", handleClickOutside);
523
+ return () => document.removeEventListener("mousedown", handleClickOutside);
524
+ }
525
+ }, [isAdminDropdownOpen]);
526
+ const handleAdminKeyDown = (event) => {
527
+ if (event.key === "ArrowDown") {
528
+ event.preventDefault();
529
+ setSelectedAdminIndex(
530
+ (prev) => prev < filteredAdmins.length - 1 ? prev + 1 : prev
531
+ );
532
+ setIsAdminDropdownOpen(true);
533
+ } else if (event.key === "ArrowUp") {
534
+ event.preventDefault();
535
+ setSelectedAdminIndex((prev) => prev > 0 ? prev - 1 : -1);
536
+ setIsAdminDropdownOpen(true);
537
+ } else if (event.key === "Enter" && selectedAdminIndex >= 0) {
538
+ event.preventDefault();
539
+ const admin = filteredAdmins[selectedAdminIndex];
540
+ if (admin) {
541
+ handleAdminSelect(admin);
542
+ }
543
+ } else if (event.key === "Escape") {
544
+ setIsAdminDropdownOpen(false);
545
+ setSelectedAdminIndex(-1);
546
+ }
547
+ };
548
+ const handleAdminSelect = (admin) => {
549
+ setSelectedAssignTo(admin.id);
550
+ setAdminSearchQuery(admin.name || admin.email);
551
+ setIsAdminDropdownOpen(false);
552
+ setSelectedAdminIndex(-1);
553
+ };
554
+ useEffect(() => {
555
+ if ((request == null ? void 0 : request.assign_to) && adminUsers.length > 0) {
556
+ const assignedAdmin = adminUsers.find((admin) => admin.id === request.assign_to);
557
+ if (assignedAdmin && !adminSearchQuery) {
558
+ setAdminSearchQuery(assignedAdmin.name || assignedAdmin.email);
559
+ }
560
+ }
561
+ }, [request == null ? void 0 : request.assign_to, adminUsers, adminSearchQuery]);
465
562
  const handleStatusUpdate = async () => {
466
563
  if (!id || !selectedStatus) {
467
564
  return;
@@ -720,18 +817,67 @@ const ContactRequestDetailPage = () => {
720
817
  /* @__PURE__ */ jsx(Text, { className: "font-medium", children: request.assign_to ? /* @__PURE__ */ jsx(Badge, { size: "small", className: "mt-1", children: request.assign_to }) : /* @__PURE__ */ jsx("span", { className: "text-ui-fg-subtle", children: "Unassigned" }) })
721
818
  ] }),
722
819
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-end", children: [
723
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
724
- /* @__PURE__ */ jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "Admin User ID" }),
725
- /* @__PURE__ */ jsx(
726
- Input,
727
- {
728
- type: "text",
729
- value: selectedAssignTo,
730
- onChange: (event) => setSelectedAssignTo(event.target.value),
731
- placeholder: "Enter admin user ID",
732
- className: "w-full"
733
- }
734
- )
820
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 relative", children: [
821
+ /* @__PURE__ */ jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "Assign To Admin" }),
822
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
823
+ /* @__PURE__ */ jsx(
824
+ Input,
825
+ {
826
+ ref: adminInputRef,
827
+ type: "text",
828
+ value: adminSearchQuery,
829
+ onChange: (event) => {
830
+ setAdminSearchQuery(event.target.value);
831
+ setIsAdminDropdownOpen(true);
832
+ setSelectedAdminIndex(-1);
833
+ },
834
+ onFocus: () => {
835
+ setIsAdminDropdownOpen(true);
836
+ if (adminUsers.length === 0) {
837
+ void fetchAdminUsers();
838
+ }
839
+ },
840
+ onKeyDown: handleAdminKeyDown,
841
+ placeholder: "Search admin by name, email, or ID...",
842
+ className: "w-full"
843
+ }
844
+ ),
845
+ isAdminDropdownOpen && /* @__PURE__ */ jsx(
846
+ "div",
847
+ {
848
+ ref: adminDropdownRef,
849
+ className: "absolute z-50 mt-1 w-full max-h-60 overflow-auto rounded-md border border-ui-border-base bg-ui-bg-base shadow-lg",
850
+ children: isLoadingAdmins ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Loading admins..." }) }) : filteredAdmins.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "py-1", children: filteredAdmins.map((admin, index) => /* @__PURE__ */ jsx(
851
+ "li",
852
+ {
853
+ className: `cursor-pointer px-4 py-3 hover:bg-ui-bg-subtle-hover ${index === selectedAdminIndex ? "bg-ui-bg-subtle-hover" : ""}`,
854
+ onClick: () => handleAdminSelect(admin),
855
+ onMouseEnter: () => setSelectedAdminIndex(index),
856
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
857
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
858
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: admin.name }),
859
+ admin.id === selectedAssignTo && /* @__PURE__ */ jsx(Badge, { size: "2xsmall", children: "Selected" })
860
+ ] }),
861
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: admin.email }),
862
+ /* @__PURE__ */ jsx(
863
+ Text,
864
+ {
865
+ size: "xsmall",
866
+ className: "text-ui-fg-muted font-mono",
867
+ children: admin.id
868
+ }
869
+ )
870
+ ] })
871
+ },
872
+ admin.id
873
+ )) }) : /* @__PURE__ */ jsx("div", { className: "p-4 text-center", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: adminSearchQuery ? "No admins found" : "Start typing to search admins" }) })
874
+ }
875
+ )
876
+ ] }),
877
+ selectedAssignTo && /* @__PURE__ */ jsxs(Text, { size: "small", className: "mt-1 text-ui-fg-subtle", children: [
878
+ "Selected Admin ID: ",
879
+ selectedAssignTo
880
+ ] })
735
881
  ] }),
736
882
  /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
737
883
  /* @__PURE__ */ jsx(
@@ -739,7 +885,7 @@ const ContactRequestDetailPage = () => {
739
885
  {
740
886
  variant: "primary",
741
887
  onClick: handleAssign,
742
- disabled: isAssigning,
888
+ disabled: isAssigning || !selectedAssignTo,
743
889
  isLoading: isAssigning,
744
890
  children: "Assign"
745
891
  }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const GET = async (req, res) => {
6
+ try {
7
+ const { q } = req.query;
8
+ const searchQuery = q ? String(q).toLowerCase() : "";
9
+ let users = [];
10
+ try {
11
+ // Resolve the EntityManager to query the database
12
+ const manager = req.scope.resolve(utils_1.ContainerRegistrationKeys.MANAGER);
13
+ if (manager) {
14
+ const knex = manager.getKnex();
15
+ if (knex) {
16
+ // Query auth_identity table for admin users
17
+ // In Medusa v2, admin users are stored in auth_identity with entity_type = 'user'
18
+ const result = await knex.raw(`
19
+ SELECT DISTINCT
20
+ ai.id,
21
+ ai.provider_metadata->>'email' as email,
22
+ ai.provider_metadata->>'first_name' as first_name,
23
+ ai.provider_metadata->>'last_name' as last_name
24
+ FROM auth_identity ai
25
+ WHERE ai.entity_type = 'user'
26
+ ORDER BY ai.created_at DESC
27
+ `);
28
+ // Handle different result formats from knex.raw()
29
+ const rows = result.rows || result[0] || [];
30
+ users = rows.map((row) => {
31
+ if (typeof row === "object" && row !== null) {
32
+ const r = row;
33
+ const firstName = r.first_name || "";
34
+ const lastName = r.last_name || "";
35
+ const name = [firstName, lastName].filter(Boolean).join(" ") || r.email || "";
36
+ return {
37
+ id: r.id || "",
38
+ email: r.email || "",
39
+ first_name: r.first_name || null,
40
+ last_name: r.last_name || null,
41
+ name,
42
+ };
43
+ }
44
+ return null;
45
+ }).filter(Boolean);
46
+ }
47
+ }
48
+ }
49
+ catch (serviceError) {
50
+ // If service resolution fails, return empty array
51
+ console.warn("Could not fetch admin users from database:", serviceError);
52
+ }
53
+ // Filter by search query if provided
54
+ if (searchQuery && users.length > 0) {
55
+ users = users.filter((user) => {
56
+ const nameMatch = user.name.toLowerCase().includes(searchQuery);
57
+ const emailMatch = user.email.toLowerCase().includes(searchQuery);
58
+ const idMatch = user.id.toLowerCase().includes(searchQuery);
59
+ return nameMatch || emailMatch || idMatch;
60
+ });
61
+ }
62
+ res.status(200).json({ users });
63
+ }
64
+ catch (error) {
65
+ // On error, return empty array so UI doesn't break
66
+ console.error("Error fetching admin users:", error);
67
+ res.status(200).json({ users: [] });
68
+ }
69
+ };
70
+ exports.GET = GET;
71
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3VzZXJzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHFEQUFxRTtBQVU5RCxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDbkUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxFQUFFLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUE7UUFDdkIsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtRQUVwRCxJQUFJLEtBQUssR0FBZ0IsRUFBRSxDQUFBO1FBRTNCLElBQUksQ0FBQztZQUNILGtEQUFrRDtZQUNsRCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDL0IsaUNBQXlCLENBQUMsT0FBTyxDQUNsQyxDQUFBO1lBRUQsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUE7Z0JBRTlCLElBQUksSUFBSSxFQUFFLENBQUM7b0JBQ1QsNENBQTRDO29CQUM1QyxrRkFBa0Y7b0JBQ2xGLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQzs7Ozs7Ozs7O1dBUzdCLENBQUMsQ0FBQTtvQkFFRixrREFBa0Q7b0JBQ2xELE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtvQkFFM0MsS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFZLEVBQUUsRUFBRTt3QkFDaEMsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxLQUFLLElBQUksRUFBRSxDQUFDOzRCQUM1QyxNQUFNLENBQUMsR0FBRyxHQUtULENBQUE7NEJBQ0QsTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUE7NEJBQ3BDLE1BQU0sUUFBUSxHQUFHLENBQUMsQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFBOzRCQUNsQyxNQUFNLElBQUksR0FBRyxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFBOzRCQUU3RSxPQUFPO2dDQUNMLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUU7Z0NBQ2QsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRTtnQ0FDcEIsVUFBVSxFQUFFLENBQUMsQ0FBQyxVQUFVLElBQUksSUFBSTtnQ0FDaEMsU0FBUyxFQUFFLENBQUMsQ0FBQyxTQUFTLElBQUksSUFBSTtnQ0FDOUIsSUFBSTs2QkFDTCxDQUFBO3dCQUNILENBQUM7d0JBQ0QsT0FBTyxJQUFJLENBQUE7b0JBQ2IsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBZ0IsQ0FBQTtnQkFDbkMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxZQUFZLEVBQUUsQ0FBQztZQUN0QixrREFBa0Q7WUFDbEQsT0FBTyxDQUFDLElBQUksQ0FBQyw0Q0FBNEMsRUFBRSxZQUFZLENBQUMsQ0FBQTtRQUMxRSxDQUFDO1FBRUQscUNBQXFDO1FBQ3JDLElBQUksV0FBVyxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDcEMsS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDNUIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUE7Z0JBQy9ELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFBO2dCQUNqRSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQTtnQkFDM0QsT0FBTyxTQUFTLElBQUksVUFBVSxJQUFJLE9BQU8sQ0FBQTtZQUMzQyxDQUFDLENBQUMsQ0FBQTtRQUNKLENBQUM7UUFFRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7SUFDakMsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixtREFBbUQ7UUFDbkQsT0FBTyxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsRUFBRSxLQUFLLENBQUMsQ0FBQTtRQUNuRCxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFBO0lBQ3JDLENBQUM7QUFDSCxDQUFDLENBQUE7QUE5RVksUUFBQSxHQUFHLE9BOEVmIn0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-contact-us",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
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",