elseware-ui 2.31.0 → 2.31.2

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/dist/index.js CHANGED
@@ -24,6 +24,7 @@ var reactBeautifulDnd = require('react-beautiful-dnd');
24
24
  var md = require('react-icons/md');
25
25
  require('@mdxeditor/editor/style.css');
26
26
  var editor = require('@mdxeditor/editor');
27
+ var bi = require('react-icons/bi');
27
28
 
28
29
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
29
30
 
@@ -15741,7 +15742,7 @@ function Tags({
15741
15742
  var Tags_default = Tags;
15742
15743
  function TextArea({
15743
15744
  placeholder,
15744
- limit,
15745
+ limit = 1e3,
15745
15746
  styles,
15746
15747
  shape,
15747
15748
  ...props
@@ -17485,6 +17486,824 @@ function ShowMore({ text, limit }) {
17485
17486
  ] });
17486
17487
  }
17487
17488
  var ShowMore_default = ShowMore;
17489
+ function CommentComposer({
17490
+ avatar,
17491
+ placeholder = "Add a comment...",
17492
+ submitLabel = "Comment",
17493
+ disabled,
17494
+ loading,
17495
+ onSubmit
17496
+ }) {
17497
+ const [value, setValue] = React4.useState("");
17498
+ const [focused, setFocused] = React4.useState(false);
17499
+ async function handleSubmit() {
17500
+ const content = value.trim();
17501
+ if (!content) {
17502
+ return;
17503
+ }
17504
+ await onSubmit?.(content);
17505
+ setValue("");
17506
+ setFocused(false);
17507
+ }
17508
+ function handleCancel() {
17509
+ setValue("");
17510
+ setFocused(false);
17511
+ }
17512
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
17513
+ /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: avatar, size: "md" }),
17514
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col gap-3", children: [
17515
+ /* @__PURE__ */ jsxRuntime.jsx(
17516
+ "textarea",
17517
+ {
17518
+ value,
17519
+ disabled: disabled || loading,
17520
+ placeholder,
17521
+ onFocus: () => setFocused(true),
17522
+ onChange: (e) => setValue(e.target.value),
17523
+ className: "\n w-full\n min-h-[56px]\n resize-none\n bg-transparent\n border-b\n border-gray-300\n dark:border-neutral-700\n outline-none\n pb-2\n text-sm\n "
17524
+ }
17525
+ ),
17526
+ (focused || value.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
17527
+ /* @__PURE__ */ jsxRuntime.jsx(
17528
+ Button_default,
17529
+ {
17530
+ text: "Cancel",
17531
+ variant: "secondary",
17532
+ appearance: "ghost",
17533
+ disabled: loading,
17534
+ onClick: handleCancel
17535
+ }
17536
+ ),
17537
+ /* @__PURE__ */ jsxRuntime.jsx(
17538
+ Button_default,
17539
+ {
17540
+ text: submitLabel,
17541
+ variant: "primary",
17542
+ loading,
17543
+ disabled: !value.trim(),
17544
+ onClick: handleSubmit
17545
+ }
17546
+ )
17547
+ ] })
17548
+ ] })
17549
+ ] });
17550
+ }
17551
+ var CommentComposer_default = CommentComposer;
17552
+ function CommentActions({
17553
+ likes = 0,
17554
+ dislikes = 0,
17555
+ liked = false,
17556
+ disliked = false,
17557
+ canReply = true,
17558
+ onLike,
17559
+ onDislike,
17560
+ onReply
17561
+ }) {
17562
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17563
+ "div",
17564
+ {
17565
+ className: "\n flex\n items-center\n gap-5\n text-sm\n text-gray-500\n dark:text-gray-400\n ",
17566
+ children: [
17567
+ /* @__PURE__ */ jsxRuntime.jsxs(
17568
+ "button",
17569
+ {
17570
+ onClick: onLike,
17571
+ className: `
17572
+ inline-flex
17573
+ items-center
17574
+ gap-1
17575
+ transition-colors
17576
+ ${liked ? "text-blue-500" : "hover:text-gray-900 dark:hover:text-gray-100"}
17577
+ `,
17578
+ children: [
17579
+ liked ? /* @__PURE__ */ jsxRuntime.jsx(bi.BiSolidLike, { size: 18 }) : /* @__PURE__ */ jsxRuntime.jsx(bi.BiLike, { size: 18 }),
17580
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: likes })
17581
+ ]
17582
+ }
17583
+ ),
17584
+ /* @__PURE__ */ jsxRuntime.jsxs(
17585
+ "button",
17586
+ {
17587
+ onClick: onDislike,
17588
+ className: `
17589
+ inline-flex
17590
+ items-center
17591
+ gap-1
17592
+ transition-colors
17593
+ ${disliked ? "text-red-500" : "hover:text-gray-900 dark:hover:text-gray-100"}
17594
+ `,
17595
+ children: [
17596
+ disliked ? /* @__PURE__ */ jsxRuntime.jsx(bi.BiSolidDislike, { size: 18 }) : /* @__PURE__ */ jsxRuntime.jsx(bi.BiDislike, { size: 18 }),
17597
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: dislikes })
17598
+ ]
17599
+ }
17600
+ ),
17601
+ canReply && /* @__PURE__ */ jsxRuntime.jsx(
17602
+ "button",
17603
+ {
17604
+ onClick: onReply,
17605
+ className: "\n font-medium\n transition-colors\n hover:text-gray-900\n dark:hover:text-gray-100\n ",
17606
+ children: "Reply"
17607
+ }
17608
+ )
17609
+ ]
17610
+ }
17611
+ );
17612
+ }
17613
+ var CommentActions_default = CommentActions;
17614
+ function CommentContent({ content }) {
17615
+ return /* @__PURE__ */ jsxRuntime.jsx(
17616
+ "div",
17617
+ {
17618
+ className: "\n text-sm\n leading-relaxed\n whitespace-pre-wrap\n break-words\n text-gray-700\n dark:text-gray-300\n ",
17619
+ children: content
17620
+ }
17621
+ );
17622
+ }
17623
+ var CommentContent_default = CommentContent;
17624
+
17625
+ // src/compositions/comment-thread/utils/formatCommentDate.ts
17626
+ function formatCommentDate(date) {
17627
+ const now = /* @__PURE__ */ new Date();
17628
+ const target = new Date(date);
17629
+ const seconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
17630
+ const intervals = [
17631
+ {
17632
+ label: "year",
17633
+ seconds: 31536e3
17634
+ },
17635
+ {
17636
+ label: "month",
17637
+ seconds: 2592e3
17638
+ },
17639
+ {
17640
+ label: "day",
17641
+ seconds: 86400
17642
+ },
17643
+ {
17644
+ label: "hour",
17645
+ seconds: 3600
17646
+ },
17647
+ {
17648
+ label: "minute",
17649
+ seconds: 60
17650
+ }
17651
+ ];
17652
+ for (const interval of intervals) {
17653
+ const count = Math.floor(seconds / interval.seconds);
17654
+ if (count >= 1) {
17655
+ return `${count} ${interval.label}${count > 1 ? "s" : ""} ago`;
17656
+ }
17657
+ }
17658
+ return "Just now";
17659
+ }
17660
+ function CommentHeader({
17661
+ avatar,
17662
+ username,
17663
+ firstName,
17664
+ lastName,
17665
+ createdAt,
17666
+ edited
17667
+ }) {
17668
+ const displayName = firstName || lastName ? `${firstName ?? ""} ${lastName ?? ""}`.trim() : username;
17669
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
17670
+ /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: avatar, size: "sm" }),
17671
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap min-w-0", children: [
17672
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-sm text-gray-900 dark:text-gray-100", children: displayName }),
17673
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
17674
+ "@",
17675
+ username
17676
+ ] }),
17677
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "\xB7" }),
17678
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: formatCommentDate(createdAt) }),
17679
+ edited && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: "(edited)" })
17680
+ ] })
17681
+ ] });
17682
+ }
17683
+ var CommentHeader_default = CommentHeader;
17684
+ function CommentMenu({
17685
+ canEdit,
17686
+ canDelete,
17687
+ canReport,
17688
+ onEdit,
17689
+ onDelete,
17690
+ onReport
17691
+ }) {
17692
+ const [open, setOpen] = React4.useState(false);
17693
+ const ref = React4.useRef(null);
17694
+ React4.useEffect(() => {
17695
+ function handleOutsideClick(event) {
17696
+ if (ref.current && !ref.current.contains(event.target)) {
17697
+ setOpen(false);
17698
+ }
17699
+ }
17700
+ document.addEventListener("mousedown", handleOutsideClick);
17701
+ return () => document.removeEventListener("mousedown", handleOutsideClick);
17702
+ }, []);
17703
+ const hasActions = canEdit || canDelete || canReport;
17704
+ if (!hasActions) {
17705
+ return null;
17706
+ }
17707
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: "relative", children: [
17708
+ /* @__PURE__ */ jsxRuntime.jsx(
17709
+ "button",
17710
+ {
17711
+ type: "button",
17712
+ onClick: () => setOpen((prev) => !prev),
17713
+ className: "\n text-gray-500\n hover:text-gray-900\n dark:hover:text-gray-100\n transition-colors\n ",
17714
+ children: /* @__PURE__ */ jsxRuntime.jsx(bi.BiDotsVerticalRounded, { size: 18 })
17715
+ }
17716
+ ),
17717
+ open && /* @__PURE__ */ jsxRuntime.jsxs(
17718
+ "div",
17719
+ {
17720
+ className: "\n absolute\n right-0\n top-full\n mt-2\n min-w-[180px]\n overflow-hidden\n rounded-xl\n border\n border-gray-200\n dark:border-neutral-800\n bg-white\n dark:bg-neutral-900\n shadow-xl\n z-50\n ",
17721
+ children: [
17722
+ canEdit && /* @__PURE__ */ jsxRuntime.jsxs(
17723
+ "button",
17724
+ {
17725
+ type: "button",
17726
+ onClick: () => {
17727
+ setOpen(false);
17728
+ onEdit?.();
17729
+ },
17730
+ className: "\n w-full\n flex\n items-center\n gap-2\n px-4\n py-3\n text-sm\n hover:bg-gray-100\n dark:hover:bg-neutral-800\n ",
17731
+ children: [
17732
+ /* @__PURE__ */ jsxRuntime.jsx(bi.BiEdit, {}),
17733
+ "Edit"
17734
+ ]
17735
+ }
17736
+ ),
17737
+ canDelete && /* @__PURE__ */ jsxRuntime.jsxs(
17738
+ "button",
17739
+ {
17740
+ type: "button",
17741
+ onClick: () => {
17742
+ setOpen(false);
17743
+ onDelete?.();
17744
+ },
17745
+ className: "\n w-full\n flex\n items-center\n gap-2\n px-4\n py-3\n text-sm\n text-red-500\n hover:bg-gray-100\n dark:hover:bg-neutral-800\n ",
17746
+ children: [
17747
+ /* @__PURE__ */ jsxRuntime.jsx(bi.BiTrash, {}),
17748
+ "Delete"
17749
+ ]
17750
+ }
17751
+ ),
17752
+ canReport && /* @__PURE__ */ jsxRuntime.jsxs(
17753
+ "button",
17754
+ {
17755
+ type: "button",
17756
+ onClick: () => {
17757
+ setOpen(false);
17758
+ onReport?.();
17759
+ },
17760
+ className: "\n w-full\n flex\n items-center\n gap-2\n px-4\n py-3\n text-sm\n hover:bg-gray-100\n dark:hover:bg-neutral-800\n ",
17761
+ children: [
17762
+ /* @__PURE__ */ jsxRuntime.jsx(bi.BiFlag, {}),
17763
+ "Report"
17764
+ ]
17765
+ }
17766
+ )
17767
+ ]
17768
+ }
17769
+ )
17770
+ ] });
17771
+ }
17772
+ var CommentMenu_default = CommentMenu;
17773
+ function CommentRepliesToggle({
17774
+ repliesCount,
17775
+ collapsed,
17776
+ onToggle
17777
+ }) {
17778
+ if (repliesCount <= 0) {
17779
+ return null;
17780
+ }
17781
+ const label = collapsed ? `View ${repliesCount} ${repliesCount === 1 ? "reply" : "replies"}` : "Hide replies";
17782
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17783
+ "button",
17784
+ {
17785
+ type: "button",
17786
+ onClick: onToggle,
17787
+ className: "\n inline-flex\n items-center\n gap-1\n w-fit\n text-sm\n font-medium\n text-blue-500\n hover:text-blue-400\n transition-colors\n ",
17788
+ children: [
17789
+ collapsed ? /* @__PURE__ */ jsxRuntime.jsx(bi.BiChevronDown, { size: 18 }) : /* @__PURE__ */ jsxRuntime.jsx(bi.BiChevronUp, { size: 18 }),
17790
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
17791
+ ]
17792
+ }
17793
+ );
17794
+ }
17795
+ var CommentRepliesToggle_default = CommentRepliesToggle;
17796
+ function ReplyComposer({
17797
+ avatar,
17798
+ username,
17799
+ loading,
17800
+ onSubmit
17801
+ }) {
17802
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
17803
+ CommentComposer_default,
17804
+ {
17805
+ avatar,
17806
+ loading,
17807
+ submitLabel: "Reply",
17808
+ placeholder: `Reply to @${username}`,
17809
+ onSubmit
17810
+ }
17811
+ ) });
17812
+ }
17813
+ var ReplyComposer_default = ReplyComposer;
17814
+
17815
+ // src/compositions/comment-thread/constants/comment.constants.ts
17816
+ var MAX_COMMENT_DEPTH = 5;
17817
+ var COMMENT_INDENTATION = 24;
17818
+ function CommentItem({
17819
+ comment,
17820
+ depth = 0,
17821
+ onLike,
17822
+ onDislike,
17823
+ onReply,
17824
+ onEdit,
17825
+ onDelete,
17826
+ onReport
17827
+ }) {
17828
+ const [collapsed, setCollapsed] = React4.useState(false);
17829
+ const [isReplying, setIsReplying] = React4.useState(false);
17830
+ const resolvedDepth = Math.min(depth, MAX_COMMENT_DEPTH);
17831
+ async function handleReply(content) {
17832
+ await onReply?.(comment, content);
17833
+ setIsReplying(false);
17834
+ }
17835
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17836
+ "div",
17837
+ {
17838
+ className: "flex flex-col gap-4",
17839
+ style: {
17840
+ paddingLeft: resolvedDepth * COMMENT_INDENTATION
17841
+ },
17842
+ children: [
17843
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-3 min-w-0", children: [
17844
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
17845
+ /* @__PURE__ */ jsxRuntime.jsx(
17846
+ CommentHeader_default,
17847
+ {
17848
+ avatar: comment.author?.avatar,
17849
+ username: comment.author?.username ?? "unknown",
17850
+ firstName: comment.author?.firstName,
17851
+ lastName: comment.author?.lastName,
17852
+ createdAt: comment.createdAt,
17853
+ edited: comment.edited
17854
+ }
17855
+ ),
17856
+ /* @__PURE__ */ jsxRuntime.jsx(
17857
+ CommentMenu_default,
17858
+ {
17859
+ canEdit: comment.permissions?.canEdit,
17860
+ canDelete: comment.permissions?.canDelete,
17861
+ canReport: comment.permissions?.canReport,
17862
+ onEdit: () => onEdit?.(comment),
17863
+ onDelete: () => onDelete?.(comment),
17864
+ onReport: () => onReport?.(comment)
17865
+ }
17866
+ )
17867
+ ] }),
17868
+ /* @__PURE__ */ jsxRuntime.jsx(CommentContent_default, { content: comment.content }),
17869
+ /* @__PURE__ */ jsxRuntime.jsx(
17870
+ CommentActions_default,
17871
+ {
17872
+ likes: comment.likes,
17873
+ dislikes: comment.dislikes,
17874
+ liked: comment.liked,
17875
+ disliked: comment.disliked,
17876
+ canReply: comment.permissions?.canReply,
17877
+ onLike: () => onLike?.(comment),
17878
+ onDislike: () => onDislike?.(comment),
17879
+ onReply: () => setIsReplying((prev) => !prev)
17880
+ }
17881
+ ),
17882
+ isReplying && /* @__PURE__ */ jsxRuntime.jsx(
17883
+ ReplyComposer_default,
17884
+ {
17885
+ avatar: comment.author?.avatar,
17886
+ username: comment.author?.username,
17887
+ onSubmit: handleReply
17888
+ }
17889
+ ),
17890
+ !!comment.replies?.length && /* @__PURE__ */ jsxRuntime.jsx(
17891
+ CommentRepliesToggle_default,
17892
+ {
17893
+ collapsed,
17894
+ repliesCount: comment.replies.length,
17895
+ onToggle: () => setCollapsed((prev) => !prev)
17896
+ }
17897
+ )
17898
+ ] }) }),
17899
+ !collapsed && !!comment.replies?.length && /* @__PURE__ */ jsxRuntime.jsx(
17900
+ "div",
17901
+ {
17902
+ className: cn(
17903
+ "border-l border-gray-200 dark:border-neutral-800",
17904
+ "pl-4 ml-5"
17905
+ ),
17906
+ children: /* @__PURE__ */ jsxRuntime.jsx(
17907
+ CommentList_default,
17908
+ {
17909
+ comments: comment.replies,
17910
+ depth: depth + 1,
17911
+ onLike,
17912
+ onDislike,
17913
+ onReply,
17914
+ onEdit,
17915
+ onDelete,
17916
+ onReport
17917
+ }
17918
+ )
17919
+ }
17920
+ )
17921
+ ]
17922
+ }
17923
+ );
17924
+ }
17925
+ var CommentItem_default = CommentItem;
17926
+ function CommentList({
17927
+ comments,
17928
+ depth = 0,
17929
+ onLike,
17930
+ onDislike,
17931
+ onReply,
17932
+ onEdit,
17933
+ onDelete,
17934
+ onReport
17935
+ }) {
17936
+ if (!comments.length) {
17937
+ return null;
17938
+ }
17939
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-8", children: comments.map((comment) => /* @__PURE__ */ jsxRuntime.jsx(
17940
+ CommentItem_default,
17941
+ {
17942
+ comment,
17943
+ depth,
17944
+ onLike,
17945
+ onDislike,
17946
+ onReply,
17947
+ onEdit,
17948
+ onDelete,
17949
+ onReport
17950
+ },
17951
+ comment.id
17952
+ )) });
17953
+ }
17954
+ var CommentList_default = CommentList;
17955
+ function EditCommentModal({
17956
+ show,
17957
+ comment,
17958
+ handleCloseModal,
17959
+ onSubmit
17960
+ }) {
17961
+ if (!comment) return null;
17962
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal_default, { title: "Edit Comment", show, handleOnClose: handleCloseModal, children: /* @__PURE__ */ jsxRuntime.jsx(
17963
+ Form,
17964
+ {
17965
+ enableReinitialize: true,
17966
+ initialValues: {
17967
+ content: comment.content
17968
+ },
17969
+ onSubmit: async (values) => {
17970
+ await onSubmit?.(comment, values.content);
17971
+ handleCloseModal();
17972
+ },
17973
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
17974
+ /* @__PURE__ */ jsxRuntime.jsx(TextArea_default, { name: "content", rows: 5, placeholder: "Comment" }),
17975
+ /* @__PURE__ */ jsxRuntime.jsx(Button_default, { type: "submit", variant: "success", text: "Save Changes" })
17976
+ ] })
17977
+ }
17978
+ ) });
17979
+ }
17980
+ var EditCommentModal_default = EditCommentModal;
17981
+ function DeleteCommentModal({
17982
+ show,
17983
+ comment,
17984
+ handleCloseModal,
17985
+ onDelete
17986
+ }) {
17987
+ if (!comment) return null;
17988
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal_default, { title: "Delete Comment", show, handleOnClose: handleCloseModal, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-5", children: [
17989
+ /* @__PURE__ */ jsxRuntime.jsx(Typography.Paragraph, { children: "Are you sure you want to permanently delete this comment?" }),
17990
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 justify-end", children: [
17991
+ /* @__PURE__ */ jsxRuntime.jsx(Button_default, { text: "Cancel", appearance: "ghost", onClick: handleCloseModal }),
17992
+ /* @__PURE__ */ jsxRuntime.jsx(
17993
+ Button_default,
17994
+ {
17995
+ text: "Delete",
17996
+ variant: "danger",
17997
+ onClick: async () => {
17998
+ await onDelete?.(comment);
17999
+ handleCloseModal();
18000
+ }
18001
+ }
18002
+ )
18003
+ ] })
18004
+ ] }) });
18005
+ }
18006
+ var DeleteCommentModal_default = DeleteCommentModal;
18007
+ var REPORT_REASONS = [
18008
+ {
18009
+ label: "Spam",
18010
+ value: "spam"
18011
+ },
18012
+ {
18013
+ label: "Harassment",
18014
+ value: "harassment"
18015
+ },
18016
+ {
18017
+ label: "Hate Speech",
18018
+ value: "hate_speech"
18019
+ },
18020
+ {
18021
+ label: "Misleading Information",
18022
+ value: "misleading_information"
18023
+ },
18024
+ {
18025
+ label: "Other",
18026
+ value: "other"
18027
+ }
18028
+ ];
18029
+ function ReportCommentModal({
18030
+ show,
18031
+ comment,
18032
+ handleCloseModal,
18033
+ onSubmit
18034
+ }) {
18035
+ if (!comment) return null;
18036
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal_default, { title: "Report Comment", show, handleOnClose: handleCloseModal, children: /* @__PURE__ */ jsxRuntime.jsx(
18037
+ Form,
18038
+ {
18039
+ initialValues: {
18040
+ reason: "",
18041
+ description: ""
18042
+ },
18043
+ onSubmit: async (values) => {
18044
+ await onSubmit?.(comment, {
18045
+ reason: values.reason,
18046
+ description: values.description
18047
+ });
18048
+ handleCloseModal();
18049
+ },
18050
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
18051
+ /* @__PURE__ */ jsxRuntime.jsx(Select_default, { name: "reason", placeholder: "Reason", options: REPORT_REASONS }),
18052
+ /* @__PURE__ */ jsxRuntime.jsx(
18053
+ TextArea_default,
18054
+ {
18055
+ name: "description",
18056
+ rows: 4,
18057
+ placeholder: "Additional details"
18058
+ }
18059
+ ),
18060
+ /* @__PURE__ */ jsxRuntime.jsx(Button_default, { type: "submit", variant: "danger", text: "Submit Report" })
18061
+ ] })
18062
+ }
18063
+ ) });
18064
+ }
18065
+ var ReportCommentModal_default = ReportCommentModal;
18066
+ function useCommentModals() {
18067
+ const [showEditModal, setShowEditModal] = React4.useState(false);
18068
+ const [showDeleteModal, setShowDeleteModal] = React4.useState(false);
18069
+ const [showReportModal, setShowReportModal] = React4.useState(false);
18070
+ return {
18071
+ showEditModal,
18072
+ openEditModal: () => setShowEditModal(true),
18073
+ closeEditModal: () => setShowEditModal(false),
18074
+ showDeleteModal,
18075
+ openDeleteModal: () => setShowDeleteModal(true),
18076
+ closeDeleteModal: () => setShowDeleteModal(false),
18077
+ showReportModal,
18078
+ openReportModal: () => setShowReportModal(true),
18079
+ closeReportModal: () => setShowReportModal(false)
18080
+ };
18081
+ }
18082
+ function useCommentSelection() {
18083
+ const [selectedComment, setSelectedComment] = React4.useState(
18084
+ null
18085
+ );
18086
+ function selectComment(comment) {
18087
+ setSelectedComment(comment);
18088
+ }
18089
+ function clearSelection() {
18090
+ setSelectedComment(null);
18091
+ }
18092
+ return {
18093
+ selectedComment,
18094
+ selectComment,
18095
+ clearSelection
18096
+ };
18097
+ }
18098
+
18099
+ // src/compositions/comment-thread/utils/buildCommentTree.ts
18100
+ function buildCommentTree(comments) {
18101
+ const map = /* @__PURE__ */ new Map();
18102
+ const roots = [];
18103
+ comments.forEach((comment) => {
18104
+ map.set(comment.id, {
18105
+ ...comment,
18106
+ replies: []
18107
+ });
18108
+ });
18109
+ comments.forEach((comment) => {
18110
+ const current = map.get(comment.id);
18111
+ if (!comment.parentCommentId) {
18112
+ roots.push(current);
18113
+ return;
18114
+ }
18115
+ const parent = map.get(comment.parentCommentId);
18116
+ if (parent) {
18117
+ parent.replies.push(current);
18118
+ }
18119
+ });
18120
+ return roots;
18121
+ }
18122
+
18123
+ // src/compositions/comment-thread/utils/updateComment.ts
18124
+ function updateComment(comments, commentId, updater) {
18125
+ return comments.map((comment) => {
18126
+ if (comment.id === commentId) {
18127
+ return updater(comment);
18128
+ }
18129
+ return {
18130
+ ...comment,
18131
+ replies: comment.replies ? updateComment(comment.replies, commentId, updater) : []
18132
+ };
18133
+ });
18134
+ }
18135
+
18136
+ // src/compositions/comment-thread/utils/removeComment.ts
18137
+ function removeComment(comments, commentId) {
18138
+ return comments.filter((comment) => comment.id !== commentId).map((comment) => ({
18139
+ ...comment,
18140
+ replies: comment.replies ? removeComment(comment.replies, commentId) : []
18141
+ }));
18142
+ }
18143
+
18144
+ // src/compositions/comment-thread/utils/insertReply.ts
18145
+ function insertReply(comments, parentId, reply) {
18146
+ return comments.map((comment) => {
18147
+ if (comment.id === parentId) {
18148
+ return {
18149
+ ...comment,
18150
+ replies: [...comment.replies || [], reply]
18151
+ };
18152
+ }
18153
+ return {
18154
+ ...comment,
18155
+ replies: comment.replies ? insertReply(comment.replies, parentId, reply) : []
18156
+ };
18157
+ });
18158
+ }
18159
+ function CommentThread({
18160
+ postId,
18161
+ currentUser,
18162
+ dataSource,
18163
+ loading = false,
18164
+ onEdit,
18165
+ onDelete,
18166
+ onReport
18167
+ }) {
18168
+ const [comments, setComments] = React4.useState([]);
18169
+ const [isLoadingComments, setIsLoadingComments] = React4.useState(true);
18170
+ const selection = useCommentSelection();
18171
+ const modals = useCommentModals();
18172
+ React4.useEffect(() => {
18173
+ async function loadComments() {
18174
+ try {
18175
+ const result = await dataSource.getComments();
18176
+ setComments(buildCommentTree(result));
18177
+ } finally {
18178
+ setIsLoadingComments(false);
18179
+ }
18180
+ }
18181
+ loadComments();
18182
+ }, [dataSource]);
18183
+ async function handleCreateComment(content) {
18184
+ const comment = await dataSource.createComment({
18185
+ content,
18186
+ parentCommentId: null
18187
+ });
18188
+ setComments((prev) => [comment, ...prev]);
18189
+ }
18190
+ async function handleReply(parentComment, content) {
18191
+ const reply = await dataSource.createComment({
18192
+ content,
18193
+ parentCommentId: parentComment.id
18194
+ });
18195
+ setComments((prev) => insertReply(prev, parentComment.id, reply));
18196
+ }
18197
+ async function handleLike(comment) {
18198
+ const result = await dataSource.toggleLike(comment.id);
18199
+ setComments(
18200
+ (prev) => updateComment(prev, comment.id, (item) => ({
18201
+ ...item,
18202
+ likes: result.likes,
18203
+ dislikes: result.dislikes,
18204
+ liked: result.liked,
18205
+ disliked: result.disliked
18206
+ }))
18207
+ );
18208
+ }
18209
+ async function handleDislike(comment) {
18210
+ const result = await dataSource.toggleDislike(comment.id);
18211
+ setComments(
18212
+ (prev) => updateComment(prev, comment.id, (item) => ({
18213
+ ...item,
18214
+ likes: result.likes,
18215
+ dislikes: result.dislikes,
18216
+ liked: result.liked,
18217
+ disliked: result.disliked
18218
+ }))
18219
+ );
18220
+ }
18221
+ async function handleUpdateComment(comment, content) {
18222
+ const updated = await dataSource.updateComment({
18223
+ id: comment.id,
18224
+ content
18225
+ });
18226
+ setComments((prev) => updateComment(prev, comment.id, () => updated));
18227
+ }
18228
+ async function handleDeleteComment(comment) {
18229
+ await dataSource.deleteComment(comment.id);
18230
+ setComments((prev) => removeComment(prev, comment.id));
18231
+ onDelete?.(comment);
18232
+ }
18233
+ async function handleReportComment(comment, payload) {
18234
+ await dataSource.reportComment?.(
18235
+ comment.id,
18236
+ payload.reason,
18237
+ payload.description
18238
+ );
18239
+ onReport?.(comment);
18240
+ }
18241
+ if (loading || isLoadingComments) {
18242
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-6", children: "Loading comments..." });
18243
+ }
18244
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18245
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-8", children: [
18246
+ /* @__PURE__ */ jsxRuntime.jsx(
18247
+ CommentComposer_default,
18248
+ {
18249
+ avatar: currentUser.avatar,
18250
+ onSubmit: handleCreateComment
18251
+ }
18252
+ ),
18253
+ /* @__PURE__ */ jsxRuntime.jsx(
18254
+ CommentList_default,
18255
+ {
18256
+ comments,
18257
+ onLike: handleLike,
18258
+ onDislike: handleDislike,
18259
+ onReply: handleReply,
18260
+ onEdit: (comment) => {
18261
+ selection.selectComment(comment);
18262
+ onEdit?.(comment);
18263
+ modals.openEditModal();
18264
+ },
18265
+ onDelete: (comment) => {
18266
+ selection.selectComment(comment);
18267
+ modals.openDeleteModal();
18268
+ },
18269
+ onReport: (comment) => {
18270
+ selection.selectComment(comment);
18271
+ onReport?.(comment);
18272
+ modals.openReportModal();
18273
+ }
18274
+ }
18275
+ )
18276
+ ] }),
18277
+ /* @__PURE__ */ jsxRuntime.jsx(
18278
+ EditCommentModal_default,
18279
+ {
18280
+ show: modals.showEditModal,
18281
+ comment: selection.selectedComment,
18282
+ handleCloseModal: modals.closeEditModal,
18283
+ onSubmit: handleUpdateComment
18284
+ }
18285
+ ),
18286
+ /* @__PURE__ */ jsxRuntime.jsx(
18287
+ DeleteCommentModal_default,
18288
+ {
18289
+ show: modals.showDeleteModal,
18290
+ comment: selection.selectedComment,
18291
+ handleCloseModal: modals.closeDeleteModal,
18292
+ onDelete: handleDeleteComment
18293
+ }
18294
+ ),
18295
+ /* @__PURE__ */ jsxRuntime.jsx(
18296
+ ReportCommentModal_default,
18297
+ {
18298
+ show: modals.showReportModal,
18299
+ comment: selection.selectedComment,
18300
+ handleCloseModal: modals.closeReportModal,
18301
+ onSubmit: handleReportComment
18302
+ }
18303
+ )
18304
+ ] });
18305
+ }
18306
+ var CommentThread_default = CommentThread;
17488
18307
  function DataViewTable({
17489
18308
  title,
17490
18309
  columns,
@@ -18322,6 +19141,7 @@ exports.CloudinaryImage = CloudinaryImage_default;
18322
19141
  exports.CloudinaryProvider = CloudinaryProvider;
18323
19142
  exports.CloudinaryVideo = CloudinaryVideo_default;
18324
19143
  exports.Code = Code;
19144
+ exports.CommentThread = CommentThread_default;
18325
19145
  exports.Content = Content;
18326
19146
  exports.ContentArea = ContentArea_default;
18327
19147
  exports.DataView = DataView;