medusa-contact-us 0.0.21 → 0.0.22
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.
- package/.medusa/server/src/admin/index.js +300 -0
- package/.medusa/server/src/admin/index.mjs +300 -0
- package/.medusa/server/src/api/admin/contact-requests/[id]/assign/route.js +54 -0
- package/.medusa/server/src/api/admin/contact-requests/[id]/comments/route.js +28 -0
- package/.medusa/server/src/api/admin/contact-requests/[id]/route.js +36 -9
- package/.medusa/server/src/api/admin/contact-requests/validators.js +9 -2
- package/.medusa/server/src/modules/contact-requests/index.js +4 -2
- package/.medusa/server/src/modules/contact-requests/migrations/Migration20241129163317.js +2 -2
- package/.medusa/server/src/modules/contact-requests/migrations/Migration20251222161335.js +27 -0
- package/.medusa/server/src/modules/contact-requests/migrations/Migration20251222161336.js +37 -0
- package/.medusa/server/src/modules/contact-requests/models/contact-request-comment.js +13 -0
- package/.medusa/server/src/modules/contact-requests/models/contact-request.js +2 -1
- package/.medusa/server/src/modules/contact-requests/service.js +92 -1
- package/.medusa/server/src/modules/contact-subscriptions/migrations/Migration20241126103000.js +2 -2
- package/package.json +8 -5
|
@@ -5,6 +5,7 @@ const adminSdk = require("@medusajs/admin-sdk");
|
|
|
5
5
|
const ui = require("@medusajs/ui");
|
|
6
6
|
const icons = require("@medusajs/icons");
|
|
7
7
|
const reactRouterDom = require("react-router-dom");
|
|
8
|
+
require("@medusajs/admin-shared");
|
|
8
9
|
const useDebounce$1 = (value, delay) => {
|
|
9
10
|
const [debouncedValue, setDebouncedValue] = react.useState(value);
|
|
10
11
|
react.useEffect(() => {
|
|
@@ -336,6 +337,7 @@ const ContactRequestsPage = () => {
|
|
|
336
337
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
337
338
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Email" }),
|
|
338
339
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Status" }),
|
|
340
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Assigned To" }),
|
|
339
341
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Source" }),
|
|
340
342
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Created" }),
|
|
341
343
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-ui-fg-muted", children: "Actions" })
|
|
@@ -358,6 +360,7 @@ const ContactRequestsPage = () => {
|
|
|
358
360
|
children: request.status.replace("_", " ")
|
|
359
361
|
}
|
|
360
362
|
) }),
|
|
363
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: request.assign_to ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", children: request.assign_to }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "—" }) }),
|
|
361
364
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: request.source ?? "storefront" }),
|
|
362
365
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-ui-fg-subtle", children: new Date(request.created_at).toLocaleString() }),
|
|
363
366
|
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -412,6 +415,7 @@ const ContactRequestDetailPage = () => {
|
|
|
412
415
|
const navigate = reactRouterDom.useNavigate();
|
|
413
416
|
const { id } = reactRouterDom.useParams();
|
|
414
417
|
const [request, setRequest] = react.useState(null);
|
|
418
|
+
const [comments, setComments] = react.useState([]);
|
|
415
419
|
const [nextAllowedStatuses, setNextAllowedStatuses] = react.useState([]);
|
|
416
420
|
const [selectedStatus, setSelectedStatus] = react.useState("");
|
|
417
421
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
@@ -419,6 +423,15 @@ const ContactRequestDetailPage = () => {
|
|
|
419
423
|
const [error, setError] = react.useState(null);
|
|
420
424
|
const [updateError, setUpdateError] = react.useState(null);
|
|
421
425
|
const [updateSuccess, setUpdateSuccess] = react.useState(false);
|
|
426
|
+
const [selectedAssignTo, setSelectedAssignTo] = react.useState("");
|
|
427
|
+
const [isAssigning, setIsAssigning] = react.useState(false);
|
|
428
|
+
const [assignError, setAssignError] = react.useState(null);
|
|
429
|
+
const [assignSuccess, setAssignSuccess] = react.useState(false);
|
|
430
|
+
const [commentText, setCommentText] = react.useState("");
|
|
431
|
+
const [commentImages, setCommentImages] = react.useState([]);
|
|
432
|
+
const [isCreatingComment, setIsCreatingComment] = react.useState(false);
|
|
433
|
+
const [commentError, setCommentError] = react.useState(null);
|
|
434
|
+
const [commentSuccess, setCommentSuccess] = react.useState(false);
|
|
422
435
|
react.useEffect(() => {
|
|
423
436
|
if (!id) {
|
|
424
437
|
navigate("/contact-requests");
|
|
@@ -437,8 +450,10 @@ const ContactRequestDetailPage = () => {
|
|
|
437
450
|
}
|
|
438
451
|
const payload = await response.json();
|
|
439
452
|
setRequest(payload.request);
|
|
453
|
+
setComments(payload.comments ?? []);
|
|
440
454
|
setNextAllowedStatuses(payload.next_allowed_statuses ?? []);
|
|
441
455
|
setSelectedStatus("");
|
|
456
|
+
setSelectedAssignTo("");
|
|
442
457
|
} catch (loadError) {
|
|
443
458
|
const message = loadError instanceof Error ? loadError.message : "Unable to load contact request";
|
|
444
459
|
setError(message);
|
|
@@ -478,6 +493,8 @@ const ContactRequestDetailPage = () => {
|
|
|
478
493
|
});
|
|
479
494
|
if (detailResponse.ok) {
|
|
480
495
|
const detailPayload = await detailResponse.json();
|
|
496
|
+
setRequest(detailPayload.request);
|
|
497
|
+
setComments(detailPayload.comments ?? []);
|
|
481
498
|
setNextAllowedStatuses(detailPayload.next_allowed_statuses ?? []);
|
|
482
499
|
}
|
|
483
500
|
} catch (updateErr) {
|
|
@@ -487,6 +504,144 @@ const ContactRequestDetailPage = () => {
|
|
|
487
504
|
setIsUpdating(false);
|
|
488
505
|
}
|
|
489
506
|
};
|
|
507
|
+
const handleAssign = async () => {
|
|
508
|
+
if (!id) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
try {
|
|
512
|
+
setIsAssigning(true);
|
|
513
|
+
setAssignError(null);
|
|
514
|
+
setAssignSuccess(false);
|
|
515
|
+
const response = await fetch(`/admin/contact-requests/${id}/assign`, {
|
|
516
|
+
method: "POST",
|
|
517
|
+
headers: {
|
|
518
|
+
"Content-Type": "application/json"
|
|
519
|
+
},
|
|
520
|
+
credentials: "include",
|
|
521
|
+
body: JSON.stringify({
|
|
522
|
+
assign_to: selectedAssignTo.trim() || null
|
|
523
|
+
})
|
|
524
|
+
});
|
|
525
|
+
if (!response.ok) {
|
|
526
|
+
const message = await response.text();
|
|
527
|
+
throw new Error(message || "Unable to assign contact request");
|
|
528
|
+
}
|
|
529
|
+
const payload = await response.json();
|
|
530
|
+
setRequest(payload.request);
|
|
531
|
+
setSelectedAssignTo("");
|
|
532
|
+
setAssignSuccess(true);
|
|
533
|
+
setTimeout(() => setAssignSuccess(false), 3e3);
|
|
534
|
+
const detailResponse = await fetch(`/admin/contact-requests/${id}`, {
|
|
535
|
+
credentials: "include"
|
|
536
|
+
});
|
|
537
|
+
if (detailResponse.ok) {
|
|
538
|
+
const detailPayload = await detailResponse.json();
|
|
539
|
+
setRequest(detailPayload.request);
|
|
540
|
+
setComments(detailPayload.comments ?? []);
|
|
541
|
+
setNextAllowedStatuses(detailPayload.next_allowed_statuses ?? []);
|
|
542
|
+
}
|
|
543
|
+
} catch (assignErr) {
|
|
544
|
+
const message = assignErr instanceof Error ? assignErr.message : "Unable to assign contact request";
|
|
545
|
+
setAssignError(message);
|
|
546
|
+
} finally {
|
|
547
|
+
setIsAssigning(false);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
const handleUnassign = async () => {
|
|
551
|
+
if (!id) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
try {
|
|
555
|
+
setIsAssigning(true);
|
|
556
|
+
setAssignError(null);
|
|
557
|
+
setAssignSuccess(false);
|
|
558
|
+
const response = await fetch(`/admin/contact-requests/${id}/assign`, {
|
|
559
|
+
method: "POST",
|
|
560
|
+
headers: {
|
|
561
|
+
"Content-Type": "application/json"
|
|
562
|
+
},
|
|
563
|
+
credentials: "include",
|
|
564
|
+
body: JSON.stringify({
|
|
565
|
+
assign_to: null
|
|
566
|
+
})
|
|
567
|
+
});
|
|
568
|
+
if (!response.ok) {
|
|
569
|
+
const message = await response.text();
|
|
570
|
+
throw new Error(message || "Unable to unassign contact request");
|
|
571
|
+
}
|
|
572
|
+
const payload = await response.json();
|
|
573
|
+
setRequest(payload.request);
|
|
574
|
+
setAssignSuccess(true);
|
|
575
|
+
setTimeout(() => setAssignSuccess(false), 3e3);
|
|
576
|
+
const detailResponse = await fetch(`/admin/contact-requests/${id}`, {
|
|
577
|
+
credentials: "include"
|
|
578
|
+
});
|
|
579
|
+
if (detailResponse.ok) {
|
|
580
|
+
const detailPayload = await detailResponse.json();
|
|
581
|
+
setRequest(detailPayload.request);
|
|
582
|
+
setComments(detailPayload.comments ?? []);
|
|
583
|
+
setNextAllowedStatuses(detailPayload.next_allowed_statuses ?? []);
|
|
584
|
+
}
|
|
585
|
+
} catch (assignErr) {
|
|
586
|
+
const message = assignErr instanceof Error ? assignErr.message : "Unable to unassign contact request";
|
|
587
|
+
setAssignError(message);
|
|
588
|
+
} finally {
|
|
589
|
+
setIsAssigning(false);
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
const handleCreateComment = async () => {
|
|
593
|
+
if (!id || !commentText.trim() && commentImages.length === 0) {
|
|
594
|
+
setCommentError("Please provide a comment or at least one image");
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
try {
|
|
598
|
+
setIsCreatingComment(true);
|
|
599
|
+
setCommentError(null);
|
|
600
|
+
setCommentSuccess(false);
|
|
601
|
+
const response = await fetch(`/admin/contact-requests/${id}/comments`, {
|
|
602
|
+
method: "POST",
|
|
603
|
+
headers: {
|
|
604
|
+
"Content-Type": "application/json"
|
|
605
|
+
},
|
|
606
|
+
credentials: "include",
|
|
607
|
+
body: JSON.stringify({
|
|
608
|
+
comment: commentText.trim() || void 0,
|
|
609
|
+
images: commentImages.filter((img) => img.trim()).length > 0 ? commentImages.filter((img) => img.trim()) : void 0
|
|
610
|
+
})
|
|
611
|
+
});
|
|
612
|
+
if (!response.ok) {
|
|
613
|
+
const message = await response.text();
|
|
614
|
+
throw new Error(message || "Unable to create comment");
|
|
615
|
+
}
|
|
616
|
+
const detailResponse = await fetch(`/admin/contact-requests/${id}`, {
|
|
617
|
+
credentials: "include"
|
|
618
|
+
});
|
|
619
|
+
if (detailResponse.ok) {
|
|
620
|
+
const detailPayload = await detailResponse.json();
|
|
621
|
+
setComments(detailPayload.comments ?? []);
|
|
622
|
+
}
|
|
623
|
+
setCommentText("");
|
|
624
|
+
setCommentImages([]);
|
|
625
|
+
setCommentSuccess(true);
|
|
626
|
+
setTimeout(() => setCommentSuccess(false), 3e3);
|
|
627
|
+
} catch (commentErr) {
|
|
628
|
+
const message = commentErr instanceof Error ? commentErr.message : "Unable to create comment";
|
|
629
|
+
setCommentError(message);
|
|
630
|
+
} finally {
|
|
631
|
+
setIsCreatingComment(false);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
const addImageInput = () => {
|
|
635
|
+
setCommentImages([...commentImages, ""]);
|
|
636
|
+
};
|
|
637
|
+
const removeImageInput = (index) => {
|
|
638
|
+
setCommentImages(commentImages.filter((_, i) => i !== index));
|
|
639
|
+
};
|
|
640
|
+
const updateImageUrl = (index, value) => {
|
|
641
|
+
const updated = [...commentImages];
|
|
642
|
+
updated[index] = value;
|
|
643
|
+
setCommentImages(updated);
|
|
644
|
+
};
|
|
490
645
|
if (isLoading) {
|
|
491
646
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "mx-auto flex w-full max-w-5xl flex-col gap-6 p-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading contact request..." }) }) }) });
|
|
492
647
|
}
|
|
@@ -558,6 +713,54 @@ const ContactRequestDetailPage = () => {
|
|
|
558
713
|
updateError && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-error", children: updateError }),
|
|
559
714
|
updateSuccess && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mt-2 text-ui-fg-success", children: "Status updated successfully" })
|
|
560
715
|
] }),
|
|
716
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
717
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Assignment" }),
|
|
718
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
719
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
720
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Currently Assigned To" }),
|
|
721
|
+
/* @__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
|
+
] }),
|
|
723
|
+
/* @__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
|
+
)
|
|
736
|
+
] }),
|
|
737
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
738
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
739
|
+
ui.Button,
|
|
740
|
+
{
|
|
741
|
+
variant: "primary",
|
|
742
|
+
onClick: handleAssign,
|
|
743
|
+
disabled: isAssigning,
|
|
744
|
+
isLoading: isAssigning,
|
|
745
|
+
children: "Assign"
|
|
746
|
+
}
|
|
747
|
+
),
|
|
748
|
+
request.assign_to && /* @__PURE__ */ jsxRuntime.jsx(
|
|
749
|
+
ui.Button,
|
|
750
|
+
{
|
|
751
|
+
variant: "secondary",
|
|
752
|
+
onClick: handleUnassign,
|
|
753
|
+
disabled: isAssigning,
|
|
754
|
+
isLoading: isAssigning,
|
|
755
|
+
children: "Unassign"
|
|
756
|
+
}
|
|
757
|
+
)
|
|
758
|
+
] })
|
|
759
|
+
] }),
|
|
760
|
+
assignError && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-error", children: assignError }),
|
|
761
|
+
assignSuccess && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-success", children: "Assignment updated successfully" })
|
|
762
|
+
] })
|
|
763
|
+
] }),
|
|
561
764
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [
|
|
562
765
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
563
766
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Contact Information" }),
|
|
@@ -631,6 +834,103 @@ const ContactRequestDetailPage = () => {
|
|
|
631
834
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: key }),
|
|
632
835
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "font-medium", children: typeof value === "string" ? value : JSON.stringify(value) })
|
|
633
836
|
] }, key)) })
|
|
837
|
+
] }),
|
|
838
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-6", children: [
|
|
839
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-4 text-lg", children: "Comments" }),
|
|
840
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 space-y-4 rounded-lg border border-ui-border-subtle bg-ui-bg-subtle p-4", children: [
|
|
841
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
842
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-2 block text-sm font-medium text-ui-fg-base", children: "Add Comment" }),
|
|
843
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
844
|
+
ui.Textarea,
|
|
845
|
+
{
|
|
846
|
+
value: commentText,
|
|
847
|
+
onChange: (event) => setCommentText(event.target.value),
|
|
848
|
+
placeholder: "Enter your comment...",
|
|
849
|
+
className: "min-h-[80px]"
|
|
850
|
+
}
|
|
851
|
+
)
|
|
852
|
+
] }),
|
|
853
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
854
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
855
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-base", children: "Images (URLs)" }),
|
|
856
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
857
|
+
ui.Button,
|
|
858
|
+
{
|
|
859
|
+
variant: "transparent",
|
|
860
|
+
size: "small",
|
|
861
|
+
onClick: addImageInput,
|
|
862
|
+
type: "button",
|
|
863
|
+
children: "Add Image URL"
|
|
864
|
+
}
|
|
865
|
+
)
|
|
866
|
+
] }),
|
|
867
|
+
commentImages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: commentImages.map((url, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
868
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
869
|
+
ui.Input,
|
|
870
|
+
{
|
|
871
|
+
type: "text",
|
|
872
|
+
value: url,
|
|
873
|
+
onChange: (event) => updateImageUrl(index, event.target.value),
|
|
874
|
+
placeholder: "https://example.com/image.jpg",
|
|
875
|
+
className: "flex-1"
|
|
876
|
+
}
|
|
877
|
+
),
|
|
878
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
879
|
+
ui.Button,
|
|
880
|
+
{
|
|
881
|
+
variant: "transparent",
|
|
882
|
+
size: "small",
|
|
883
|
+
onClick: () => removeImageInput(index),
|
|
884
|
+
type: "button",
|
|
885
|
+
children: "Remove"
|
|
886
|
+
}
|
|
887
|
+
)
|
|
888
|
+
] }, index)) })
|
|
889
|
+
] }),
|
|
890
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
891
|
+
ui.Button,
|
|
892
|
+
{
|
|
893
|
+
variant: "primary",
|
|
894
|
+
onClick: handleCreateComment,
|
|
895
|
+
disabled: isCreatingComment || !commentText.trim() && commentImages.filter((img) => img.trim()).length === 0,
|
|
896
|
+
isLoading: isCreatingComment,
|
|
897
|
+
children: "Add Comment"
|
|
898
|
+
}
|
|
899
|
+
),
|
|
900
|
+
commentError && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-error", children: commentError }),
|
|
901
|
+
commentSuccess && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-success", children: "Comment added successfully" })
|
|
902
|
+
] }),
|
|
903
|
+
comments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
904
|
+
"div",
|
|
905
|
+
{
|
|
906
|
+
className: "rounded-lg border border-ui-border-subtle bg-ui-bg-subtle p-4",
|
|
907
|
+
children: [
|
|
908
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
909
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", children: comment.admin_id }),
|
|
910
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: new Date(comment.created_at).toLocaleString() })
|
|
911
|
+
] }) }),
|
|
912
|
+
comment.comment && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-2 whitespace-pre-wrap", children: comment.comment }),
|
|
913
|
+
comment.images && comment.images.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 space-y-2", children: [
|
|
914
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Images:" }),
|
|
915
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: comment.images.map((imageUrl, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
916
|
+
"a",
|
|
917
|
+
{
|
|
918
|
+
href: imageUrl,
|
|
919
|
+
target: "_blank",
|
|
920
|
+
rel: "noopener noreferrer",
|
|
921
|
+
className: "text-sm text-ui-fg-interactive hover:underline",
|
|
922
|
+
children: [
|
|
923
|
+
"Image ",
|
|
924
|
+
index + 1
|
|
925
|
+
]
|
|
926
|
+
},
|
|
927
|
+
index
|
|
928
|
+
)) })
|
|
929
|
+
] })
|
|
930
|
+
]
|
|
931
|
+
},
|
|
932
|
+
comment.id
|
|
933
|
+
)) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "No comments yet" })
|
|
634
934
|
] })
|
|
635
935
|
] }) });
|
|
636
936
|
};
|