elseware-ui 2.36.9 → 2.37.0

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.mjs CHANGED
@@ -18,7 +18,7 @@ import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
18
18
  import { MdUpload, MdOutlineDone, MdOutlineRemoveCircleOutline } from 'react-icons/md';
19
19
  import '@mdxeditor/editor/style.css';
20
20
  import { MDXEditor, headingsPlugin, linkPlugin, listsPlugin, imagePlugin, tablePlugin, linkDialogPlugin, thematicBreakPlugin, quotePlugin, toolbarPlugin, UndoRedo, Separator, BlockTypeSelect, BoldItalicUnderlineToggles, StrikeThroughSupSubToggles, ListsToggle, CreateLink, InsertImage, InsertTable, InsertThematicBreak, markdownShortcutPlugin, frontmatterPlugin, codeBlockPlugin, codeMirrorPlugin } from '@mdxeditor/editor';
21
- import { BiChevronDown, BiChevronUp, BiSolidLike, BiLike, BiSolidDislike, BiDislike, BiDotsVerticalRounded, BiEdit, BiTrash, BiFlag } from 'react-icons/bi';
21
+ import { BiCheckCircle, BiXCircle, BiChevronDown, BiChevronUp, BiSolidLike, BiLike, BiSolidDislike, BiDislike, BiDotsVerticalRounded, BiReply, BiEdit, BiTrash, BiFlag } from 'react-icons/bi';
22
22
 
23
23
  // node_modules/clsx/dist/clsx.mjs
24
24
  function r(e) {
@@ -22948,6 +22948,1573 @@ var TopNav = ({
22948
22948
  };
22949
22949
  return /* @__PURE__ */ jsx("div", { className: "flex items-center", children: items.map(renderNode) });
22950
22950
  };
22951
+ function ReviewForm({
22952
+ initialValues,
22953
+ placeholder = "Write your review...",
22954
+ submitLabel = "Submit",
22955
+ cancelLabel = "Cancel",
22956
+ loading = false,
22957
+ disabled = false,
22958
+ autoFocus = false,
22959
+ config,
22960
+ onSubmit,
22961
+ onCancel
22962
+ }) {
22963
+ const [content, setContent] = useState(initialValues?.content ?? "");
22964
+ const [rating, setRating] = useState(initialValues?.rating ?? 0);
22965
+ const [isRecommended, setIsRecommended] = useState(
22966
+ initialValues?.isRecommended ?? true
22967
+ );
22968
+ const [error, setError] = useState("");
22969
+ const contentLength = content.trim().length;
22970
+ const ratingItems = useMemo(() => {
22971
+ return Array.from(
22972
+ {
22973
+ length: config.maxRating
22974
+ },
22975
+ (_, index) => index + 1
22976
+ );
22977
+ }, [config.maxRating]);
22978
+ useEffect(() => {
22979
+ setContent(initialValues?.content ?? "");
22980
+ setRating(initialValues?.rating ?? 0);
22981
+ setIsRecommended(initialValues?.isRecommended ?? true);
22982
+ setError("");
22983
+ }, [
22984
+ initialValues?.content,
22985
+ initialValues?.rating,
22986
+ initialValues?.isRecommended
22987
+ ]);
22988
+ function validate() {
22989
+ const trimmedContent = content.trim();
22990
+ if (trimmedContent.length < config.minContentLength) {
22991
+ return `Review must be at least ${config.minContentLength} characters.`;
22992
+ }
22993
+ if (trimmedContent.length > config.maxContentLength) {
22994
+ return `Review cannot be more than ${config.maxContentLength} characters.`;
22995
+ }
22996
+ if (rating < config.minRating) {
22997
+ return "Please select a rating.";
22998
+ }
22999
+ return "";
23000
+ }
23001
+ async function handleSubmit() {
23002
+ const nextError = validate();
23003
+ if (nextError) {
23004
+ setError(nextError);
23005
+ return;
23006
+ }
23007
+ const values = {
23008
+ content: content.trim(),
23009
+ rating,
23010
+ isRecommended: config.allowRecommendation ? isRecommended : void 0
23011
+ };
23012
+ await onSubmit(values);
23013
+ }
23014
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
23015
+ /* @__PURE__ */ jsx(
23016
+ "textarea",
23017
+ {
23018
+ value: content,
23019
+ disabled: disabled || loading,
23020
+ autoFocus,
23021
+ placeholder,
23022
+ maxLength: config.maxContentLength,
23023
+ onChange: (event) => {
23024
+ setContent(event.target.value);
23025
+ setError("");
23026
+ },
23027
+ className: "min-h-[120px] w-full resize-none rounded-xl border border-gray-300 bg-white px-4 py-3 text-sm text-gray-900 outline-none transition-colors placeholder:text-gray-400 focus:border-blue-500 disabled:cursor-not-allowed disabled:opacity-60 dark:border-neutral-700 dark:bg-neutral-900 dark:text-gray-100 dark:placeholder:text-gray-500"
23028
+ }
23029
+ ),
23030
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 text-xs text-gray-500 dark:text-gray-400", children: [
23031
+ /* @__PURE__ */ jsxs("span", { children: [
23032
+ contentLength,
23033
+ "/",
23034
+ config.maxContentLength
23035
+ ] }),
23036
+ error && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: error })
23037
+ ] }),
23038
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
23039
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: "Rating" }),
23040
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: ratingItems.map((item) => {
23041
+ const active = item <= rating;
23042
+ return /* @__PURE__ */ jsx(
23043
+ "button",
23044
+ {
23045
+ type: "button",
23046
+ disabled: disabled || loading,
23047
+ onClick: () => {
23048
+ setRating(item);
23049
+ setError("");
23050
+ },
23051
+ className: `
23052
+ text-2xl leading-none transition-transform disabled:cursor-not-allowed disabled:opacity-60
23053
+ ${active ? "text-yellow-400" : "text-gray-300 dark:text-neutral-700"}
23054
+ hover:scale-110
23055
+ `,
23056
+ "aria-label": `Rate ${item} out of ${config.maxRating}`,
23057
+ children: "\u2605"
23058
+ },
23059
+ item
23060
+ );
23061
+ }) })
23062
+ ] }),
23063
+ config.allowRecommendation && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
23064
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: "Do you recommend this?" }),
23065
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-3", children: [
23066
+ /* @__PURE__ */ jsxs("label", { className: "inline-flex cursor-pointer items-center gap-2 text-sm text-gray-700 dark:text-gray-300", children: [
23067
+ /* @__PURE__ */ jsx(
23068
+ "input",
23069
+ {
23070
+ type: "radio",
23071
+ checked: isRecommended,
23072
+ disabled: disabled || loading,
23073
+ onChange: () => setIsRecommended(true)
23074
+ }
23075
+ ),
23076
+ "Yes"
23077
+ ] }),
23078
+ /* @__PURE__ */ jsxs("label", { className: "inline-flex cursor-pointer items-center gap-2 text-sm text-gray-700 dark:text-gray-300", children: [
23079
+ /* @__PURE__ */ jsx(
23080
+ "input",
23081
+ {
23082
+ type: "radio",
23083
+ checked: !isRecommended,
23084
+ disabled: disabled || loading,
23085
+ onChange: () => setIsRecommended(false)
23086
+ }
23087
+ ),
23088
+ "No"
23089
+ ] })
23090
+ ] })
23091
+ ] }),
23092
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
23093
+ onCancel && /* @__PURE__ */ jsx(
23094
+ Button_default,
23095
+ {
23096
+ text: cancelLabel,
23097
+ variant: "secondary",
23098
+ appearance: "ghost",
23099
+ disabled: loading,
23100
+ onClick: onCancel
23101
+ }
23102
+ ),
23103
+ /* @__PURE__ */ jsx(
23104
+ Button_default,
23105
+ {
23106
+ text: submitLabel,
23107
+ variant: "primary",
23108
+ loading,
23109
+ disabled: disabled || !content.trim() || rating < config.minRating,
23110
+ onClick: handleSubmit
23111
+ }
23112
+ )
23113
+ ] })
23114
+ ] });
23115
+ }
23116
+ var ReviewForm_default = ReviewForm;
23117
+ function ReviewComposer({
23118
+ currentUser,
23119
+ placeholder = "Write your review...",
23120
+ submitLabel = "Post Review",
23121
+ loading = false,
23122
+ disabled = false,
23123
+ config,
23124
+ onLoginClick,
23125
+ onSubmit
23126
+ }) {
23127
+ if (!currentUser) {
23128
+ return /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-gray-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
23129
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Please login to post your review." }),
23130
+ onLoginClick && /* @__PURE__ */ jsx(Button_default, { text: "Login", variant: "primary", onClick: onLoginClick })
23131
+ ] }) });
23132
+ }
23133
+ return /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-gray-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
23134
+ /* @__PURE__ */ jsx(Avatar, { src: currentUser.avatar, size: "md" }),
23135
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
23136
+ ReviewForm_default,
23137
+ {
23138
+ placeholder,
23139
+ submitLabel,
23140
+ loading,
23141
+ disabled,
23142
+ config,
23143
+ onSubmit
23144
+ }
23145
+ ) })
23146
+ ] }) });
23147
+ }
23148
+ var ReviewComposer_default = ReviewComposer;
23149
+
23150
+ // src/compositions/review-thread/utils/formatReviewDate.ts
23151
+ function formatReviewDate(date, format = "relative") {
23152
+ if (!date) {
23153
+ return "";
23154
+ }
23155
+ const target = new Date(date);
23156
+ if (Number.isNaN(target.getTime())) {
23157
+ return "";
23158
+ }
23159
+ if (format === "absolute") {
23160
+ return target.toLocaleString();
23161
+ }
23162
+ const now = /* @__PURE__ */ new Date();
23163
+ const seconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
23164
+ if (seconds < 60) {
23165
+ return "Just now";
23166
+ }
23167
+ const intervals = [
23168
+ {
23169
+ label: "year",
23170
+ seconds: 31536e3
23171
+ },
23172
+ {
23173
+ label: "month",
23174
+ seconds: 2592e3
23175
+ },
23176
+ {
23177
+ label: "day",
23178
+ seconds: 86400
23179
+ },
23180
+ {
23181
+ label: "hour",
23182
+ seconds: 3600
23183
+ },
23184
+ {
23185
+ label: "minute",
23186
+ seconds: 60
23187
+ }
23188
+ ];
23189
+ for (const interval of intervals) {
23190
+ const count = Math.floor(seconds / interval.seconds);
23191
+ if (count >= 1) {
23192
+ return `${count} ${interval.label}${count > 1 ? "s" : ""} ago`;
23193
+ }
23194
+ }
23195
+ return "Just now";
23196
+ }
23197
+
23198
+ // src/compositions/review-thread/utils/reviewState.ts
23199
+ function prependReview(reviews, review) {
23200
+ return [review, ...reviews.filter((item) => item.id !== review.id)];
23201
+ }
23202
+ function appendReview(reviews, review) {
23203
+ return [...reviews.filter((item) => item.id !== review.id), review];
23204
+ }
23205
+ function updateReview(reviews, reviewId, updater) {
23206
+ return reviews.map(
23207
+ (review) => review.id === reviewId ? updater(review) : review
23208
+ );
23209
+ }
23210
+ function replaceReview(reviews, nextReview) {
23211
+ return updateReview(reviews, nextReview.id, () => nextReview);
23212
+ }
23213
+ function removeReview(reviews, reviewId) {
23214
+ return reviews.filter((review) => review.id !== reviewId);
23215
+ }
23216
+ function findReview(reviews, reviewId) {
23217
+ return reviews.find((review) => review.id === reviewId);
23218
+ }
23219
+ function upsertReview(reviews, review) {
23220
+ const exists = reviews.some((item) => item.id === review.id);
23221
+ if (!exists) {
23222
+ return prependReview(reviews, review);
23223
+ }
23224
+ return replaceReview(reviews, review);
23225
+ }
23226
+
23227
+ // src/compositions/review-thread/utils/reviewReplyState.ts
23228
+ function addReviewReply(review, reply, maxReplies = 1) {
23229
+ const replies = review.replies ?? [];
23230
+ return {
23231
+ ...review,
23232
+ replies: [reply, ...replies.filter((item) => item.id !== reply.id)].slice(
23233
+ 0,
23234
+ maxReplies
23235
+ )
23236
+ };
23237
+ }
23238
+ function updateReviewReply(review, replyId, updater) {
23239
+ return {
23240
+ ...review,
23241
+ replies: (review.replies ?? []).map(
23242
+ (reply) => reply.id === replyId ? updater(reply) : reply
23243
+ )
23244
+ };
23245
+ }
23246
+ function replaceReviewReply(review, nextReply) {
23247
+ return updateReviewReply(review, nextReply.id, () => nextReply);
23248
+ }
23249
+ function removeReviewReply(review, replyId) {
23250
+ return {
23251
+ ...review,
23252
+ replies: (review.replies ?? []).filter((reply) => reply.id !== replyId)
23253
+ };
23254
+ }
23255
+ function hasReviewReply(review, replyId) {
23256
+ return (review.replies ?? []).some((reply) => reply.id === replyId);
23257
+ }
23258
+
23259
+ // src/compositions/review-thread/utils/reviewPermissions.ts
23260
+ function canEditReview(review) {
23261
+ return review.permissions?.canEdit ?? false;
23262
+ }
23263
+ function canDeleteReview(review) {
23264
+ return review.permissions?.canDelete ?? false;
23265
+ }
23266
+ function canReportReview(review) {
23267
+ return review.permissions?.canReport ?? false;
23268
+ }
23269
+ function canReplyToReview(review) {
23270
+ return review.permissions?.canReply ?? false;
23271
+ }
23272
+ function canEditReviewReply(reply) {
23273
+ return reply.permissions?.canEdit ?? false;
23274
+ }
23275
+ function canDeleteReviewReply(reply) {
23276
+ return reply.permissions?.canDelete ?? false;
23277
+ }
23278
+ function canReportReviewReply(reply) {
23279
+ return reply.permissions?.canReport ?? false;
23280
+ }
23281
+
23282
+ // src/compositions/review-thread/utils/normalizeReview.ts
23283
+ function normalizeReviewAuthor(author) {
23284
+ if (!author) {
23285
+ return null;
23286
+ }
23287
+ return {
23288
+ id: String(author.id ?? author._id ?? ""),
23289
+ username: author.username,
23290
+ avatar: author.avatar,
23291
+ firstName: author.firstName,
23292
+ lastName: author.lastName,
23293
+ role: author.role
23294
+ };
23295
+ }
23296
+ function normalizeReviewReply(raw, fallback) {
23297
+ return {
23298
+ id: String(raw.id ?? raw._id ?? ""),
23299
+ targetId: String(raw.targetId ?? fallback.targetId),
23300
+ reviewId: String(raw.reviewId ?? fallback.reviewId),
23301
+ content: String(raw.content ?? raw.replyText ?? raw.responseText ?? ""),
23302
+ createdAt: String(raw.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()),
23303
+ updatedAt: raw.updatedAt,
23304
+ edited: raw.edited ?? false,
23305
+ author: normalizeReviewAuthor(raw.author ?? raw.repliedBy ?? null),
23306
+ authorLabel: raw.authorLabel,
23307
+ permissions: raw.permissions
23308
+ };
23309
+ }
23310
+ function normalizeReview(raw, fallbackTargetId = "") {
23311
+ const id = String(raw.id ?? raw._id ?? "");
23312
+ const targetId = String(
23313
+ raw.targetId ?? raw.gameSlug ?? raw.productSlug ?? raw.courseId ?? fallbackTargetId
23314
+ );
23315
+ const replies = raw.replies ? raw.replies.map(
23316
+ (reply) => normalizeReviewReply(reply, {
23317
+ targetId,
23318
+ reviewId: id
23319
+ })
23320
+ ) : raw.ownerReply ? [
23321
+ normalizeReviewReply(raw.ownerReply, {
23322
+ targetId,
23323
+ reviewId: id
23324
+ })
23325
+ ] : [];
23326
+ return {
23327
+ id,
23328
+ targetId,
23329
+ content: String(raw.content ?? raw.reviewText ?? ""),
23330
+ rating: Number(raw.rating ?? 0),
23331
+ isRecommended: raw.isRecommended,
23332
+ createdAt: String(raw.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()),
23333
+ updatedAt: raw.updatedAt,
23334
+ edited: raw.edited ?? false,
23335
+ author: normalizeReviewAuthor(raw.author ?? raw.reviewedBy ?? null),
23336
+ replies,
23337
+ permissions: raw.permissions
23338
+ };
23339
+ }
23340
+ function ReviewHeader({ review, config }) {
23341
+ const author = review.author;
23342
+ const displayName = author?.firstName || author?.lastName ? `${author?.firstName ?? ""} ${author?.lastName ?? ""}`.trim() : author?.username ?? "Unknown";
23343
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
23344
+ /* @__PURE__ */ jsx(Avatar, { src: author?.avatar, size: "sm" }),
23345
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
23346
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [
23347
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-gray-900 dark:text-gray-100", children: displayName }),
23348
+ author?.username && /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
23349
+ "@",
23350
+ author.username
23351
+ ] }),
23352
+ author?.role && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600 dark:bg-neutral-800 dark:text-gray-300", children: author.role })
23353
+ ] }),
23354
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-gray-500 dark:text-gray-400", children: [
23355
+ /* @__PURE__ */ jsx("span", { children: formatReviewDate(review.createdAt, config.dateFormat) }),
23356
+ review.edited && /* @__PURE__ */ jsx("span", { children: "(edited)" })
23357
+ ] })
23358
+ ] })
23359
+ ] });
23360
+ }
23361
+ var ReviewHeader_default = ReviewHeader;
23362
+ function ReviewContent({ review }) {
23363
+ return /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap break-words text-sm leading-6 text-gray-700 dark:text-gray-300", children: review.content });
23364
+ }
23365
+ var ReviewContent_default = ReviewContent;
23366
+ function ReviewRating({ rating, maxRating }) {
23367
+ const items = Array.from(
23368
+ {
23369
+ length: maxRating
23370
+ },
23371
+ (_, index) => index + 1
23372
+ );
23373
+ return /* @__PURE__ */ jsx(
23374
+ "div",
23375
+ {
23376
+ className: "inline-flex items-center gap-0.5",
23377
+ "aria-label": `${rating} out of ${maxRating}`,
23378
+ children: items.map((item) => /* @__PURE__ */ jsx(
23379
+ "span",
23380
+ {
23381
+ className: item <= rating ? "text-sm text-yellow-400" : "text-sm text-gray-300 dark:text-neutral-700",
23382
+ children: "\u2605"
23383
+ },
23384
+ item
23385
+ ))
23386
+ }
23387
+ );
23388
+ }
23389
+ var ReviewRating_default = ReviewRating;
23390
+ function ReviewRecommendation({ isRecommended }) {
23391
+ if (typeof isRecommended !== "boolean") {
23392
+ return null;
23393
+ }
23394
+ return /* @__PURE__ */ jsxs(
23395
+ "span",
23396
+ {
23397
+ className: `
23398
+ inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-medium
23399
+ ${isRecommended ? "bg-green-500/10 text-green-500" : "bg-red-500/10 text-red-500"}
23400
+ `,
23401
+ children: [
23402
+ isRecommended ? /* @__PURE__ */ jsx(BiCheckCircle, { size: 16 }) : /* @__PURE__ */ jsx(BiXCircle, { size: 16 }),
23403
+ isRecommended ? "Recommended" : "Not Recommended"
23404
+ ]
23405
+ }
23406
+ );
23407
+ }
23408
+ var ReviewRecommendation_default = ReviewRecommendation;
23409
+ function MyReviewPanel({
23410
+ currentUser,
23411
+ myReview,
23412
+ loading = false,
23413
+ disabled = false,
23414
+ config,
23415
+ components,
23416
+ onLoginClick,
23417
+ onCreateReview,
23418
+ onUpdateReview,
23419
+ onEditReview,
23420
+ onDeleteReview
23421
+ }) {
23422
+ const [editing, setEditing] = useState(false);
23423
+ const ComposerComponent = components?.Composer ?? ReviewComposer_default;
23424
+ const FormComponent = components?.Form ?? ReviewForm_default;
23425
+ const HeaderComponent = components?.Header ?? ReviewHeader_default;
23426
+ const ContentComponent = components?.Content ?? ReviewContent_default;
23427
+ const RatingComponent = components?.Rating ?? ReviewRating_default;
23428
+ const RecommendationComponent = components?.Recommendation ?? ReviewRecommendation_default;
23429
+ async function handleCreateReview(values) {
23430
+ await onCreateReview(values);
23431
+ }
23432
+ async function handleUpdateReview(values) {
23433
+ if (!myReview) {
23434
+ return;
23435
+ }
23436
+ await onUpdateReview(myReview, values);
23437
+ setEditing(false);
23438
+ }
23439
+ function handleEdit() {
23440
+ if (!myReview) {
23441
+ return;
23442
+ }
23443
+ if (onEditReview) {
23444
+ onEditReview(myReview);
23445
+ return;
23446
+ }
23447
+ setEditing(true);
23448
+ }
23449
+ function handleDelete() {
23450
+ if (!myReview) {
23451
+ return;
23452
+ }
23453
+ onDeleteReview?.(myReview);
23454
+ }
23455
+ if (!config.showMyReviewPanel) {
23456
+ return null;
23457
+ }
23458
+ if (!myReview) {
23459
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
23460
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: "My Review" }),
23461
+ /* @__PURE__ */ jsx(
23462
+ ComposerComponent,
23463
+ {
23464
+ currentUser,
23465
+ placeholder: "Write your review...",
23466
+ submitLabel: "Post Review",
23467
+ loading,
23468
+ disabled,
23469
+ config,
23470
+ onLoginClick,
23471
+ onSubmit: handleCreateReview
23472
+ }
23473
+ )
23474
+ ] });
23475
+ }
23476
+ if (editing) {
23477
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
23478
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: "Update My Review" }),
23479
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-gray-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsx(
23480
+ FormComponent,
23481
+ {
23482
+ initialValues: {
23483
+ content: myReview.content,
23484
+ rating: myReview.rating,
23485
+ isRecommended: myReview.isRecommended
23486
+ },
23487
+ placeholder: "Update your review...",
23488
+ submitLabel: "Update Review",
23489
+ loading,
23490
+ disabled,
23491
+ autoFocus: true,
23492
+ config,
23493
+ onSubmit: handleUpdateReview,
23494
+ onCancel: () => setEditing(false)
23495
+ }
23496
+ ) })
23497
+ ] });
23498
+ }
23499
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
23500
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: "My Review" }),
23501
+ /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-gray-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
23502
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
23503
+ /* @__PURE__ */ jsx(HeaderComponent, { review: myReview, config }),
23504
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
23505
+ /* @__PURE__ */ jsx(
23506
+ Button_default,
23507
+ {
23508
+ text: "Edit",
23509
+ variant: "secondary",
23510
+ appearance: "ghost",
23511
+ disabled: disabled || loading,
23512
+ onClick: handleEdit
23513
+ }
23514
+ ),
23515
+ onDeleteReview && /* @__PURE__ */ jsx(
23516
+ Button_default,
23517
+ {
23518
+ text: "Delete",
23519
+ variant: "danger",
23520
+ appearance: "ghost",
23521
+ disabled: disabled || loading,
23522
+ onClick: handleDelete
23523
+ }
23524
+ )
23525
+ ] })
23526
+ ] }),
23527
+ /* @__PURE__ */ jsx(ContentComponent, { review: myReview }),
23528
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
23529
+ /* @__PURE__ */ jsx(
23530
+ RatingComponent,
23531
+ {
23532
+ rating: myReview.rating,
23533
+ maxRating: config.maxRating
23534
+ }
23535
+ ),
23536
+ config.allowRecommendation && /* @__PURE__ */ jsx(
23537
+ RecommendationComponent,
23538
+ {
23539
+ isRecommended: myReview.isRecommended
23540
+ }
23541
+ )
23542
+ ] })
23543
+ ] }) })
23544
+ ] });
23545
+ }
23546
+ var MyReviewPanel_default = MyReviewPanel;
23547
+ function ReviewMenuItem({
23548
+ icon,
23549
+ name,
23550
+ badge,
23551
+ to,
23552
+ navigate,
23553
+ className,
23554
+ onClick,
23555
+ style
23556
+ }) {
23557
+ return /* @__PURE__ */ jsx(
23558
+ MenuItem,
23559
+ {
23560
+ icon,
23561
+ name,
23562
+ badge,
23563
+ to,
23564
+ navigate,
23565
+ onClick,
23566
+ style,
23567
+ className
23568
+ }
23569
+ );
23570
+ }
23571
+ function ReviewMenu({
23572
+ open,
23573
+ setOpen,
23574
+ canEdit,
23575
+ canDelete,
23576
+ canReport,
23577
+ canReply,
23578
+ onEdit,
23579
+ onDelete,
23580
+ onReport,
23581
+ onReply
23582
+ }) {
23583
+ const ref = useRef(null);
23584
+ useClickOutside(ref, () => setOpen(false));
23585
+ const items = [];
23586
+ if (canEdit) {
23587
+ items.push({
23588
+ type: "item",
23589
+ icon: /* @__PURE__ */ jsx(BiEdit, {}),
23590
+ name: "Edit Review",
23591
+ component: ReviewMenuItem,
23592
+ onClick: () => {
23593
+ setOpen(false);
23594
+ onEdit?.();
23595
+ },
23596
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800"
23597
+ });
23598
+ }
23599
+ if (canDelete) {
23600
+ items.push({
23601
+ type: "item",
23602
+ icon: /* @__PURE__ */ jsx(BiTrash, {}),
23603
+ name: "Delete Review",
23604
+ component: ReviewMenuItem,
23605
+ onClick: () => {
23606
+ setOpen(false);
23607
+ onDelete?.();
23608
+ },
23609
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm text-red-500 hover:bg-gray-100 dark:hover:bg-neutral-800"
23610
+ });
23611
+ }
23612
+ if (canReport) {
23613
+ items.push({
23614
+ type: "item",
23615
+ icon: /* @__PURE__ */ jsx(BiFlag, {}),
23616
+ name: "Report Review",
23617
+ component: ReviewMenuItem,
23618
+ onClick: () => {
23619
+ setOpen(false);
23620
+ onReport?.();
23621
+ },
23622
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800"
23623
+ });
23624
+ }
23625
+ if (canReply) {
23626
+ items.push({
23627
+ type: "item",
23628
+ icon: /* @__PURE__ */ jsx(BiReply, {}),
23629
+ name: "Reply as Owner",
23630
+ component: ReviewMenuItem,
23631
+ onClick: () => {
23632
+ setOpen(false);
23633
+ onReply?.();
23634
+ },
23635
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800"
23636
+ });
23637
+ }
23638
+ if (!items.length) {
23639
+ return null;
23640
+ }
23641
+ return /* @__PURE__ */ jsxs("div", { ref, className: "relative", children: [
23642
+ /* @__PURE__ */ jsx(
23643
+ "button",
23644
+ {
23645
+ type: "button",
23646
+ onClick: () => setOpen(!open),
23647
+ className: "text-gray-500 transition-colors hover:text-gray-900 dark:hover:text-gray-100",
23648
+ "aria-label": "Review options",
23649
+ children: /* @__PURE__ */ jsx(BiDotsVerticalRounded, { size: 20 })
23650
+ }
23651
+ ),
23652
+ /* @__PURE__ */ jsx(Transition.TransitionDropdown, { visibility: open, children: /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-full z-50 mt-2 min-w-[190px] overflow-hidden rounded-xl border border-gray-200 bg-white shadow-xl dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsx(Menu, { items }) }) })
23653
+ ] });
23654
+ }
23655
+ var ReviewMenu_default = ReviewMenu;
23656
+ function ReviewActions({ canReply, onReply }) {
23657
+ if (!canReply) {
23658
+ return null;
23659
+ }
23660
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsxs(
23661
+ "button",
23662
+ {
23663
+ type: "button",
23664
+ onClick: onReply,
23665
+ className: "inline-flex items-center gap-1 font-medium transition-colors hover:text-gray-900 dark:hover:text-gray-100",
23666
+ children: [
23667
+ /* @__PURE__ */ jsx(BiReply, { size: 18 }),
23668
+ "Reply as Owner"
23669
+ ]
23670
+ }
23671
+ ) });
23672
+ }
23673
+ var ReviewActions_default = ReviewActions;
23674
+ function ReviewReplyHeader({ reply, config }) {
23675
+ const author = reply.author;
23676
+ const displayName = author?.firstName || author?.lastName ? `${author?.firstName ?? ""} ${author?.lastName ?? ""}`.trim() : author?.username ?? "Unknown";
23677
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
23678
+ /* @__PURE__ */ jsx(Avatar, { src: author?.avatar, size: "sm" }),
23679
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
23680
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [
23681
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-gray-900 dark:text-gray-100", children: displayName }),
23682
+ (reply.authorLabel || author?.role) && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-blue-500/10 px-2 py-0.5 text-xs font-medium text-blue-500", children: reply.authorLabel ?? author?.role }),
23683
+ author?.username && /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
23684
+ "@",
23685
+ author.username
23686
+ ] })
23687
+ ] }),
23688
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-gray-500 dark:text-gray-400", children: [
23689
+ /* @__PURE__ */ jsx("span", { children: formatReviewDate(reply.createdAt, config.dateFormat) }),
23690
+ reply.edited && /* @__PURE__ */ jsx("span", { children: "(edited)" })
23691
+ ] })
23692
+ ] })
23693
+ ] });
23694
+ }
23695
+ var ReviewReplyHeader_default = ReviewReplyHeader;
23696
+ function ReviewReplyContent({ reply }) {
23697
+ return /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap break-words text-sm leading-6 text-gray-700 dark:text-gray-300", children: reply.content });
23698
+ }
23699
+ var ReviewReplyContent_default = ReviewReplyContent;
23700
+ function ReviewReplyMenuItem({
23701
+ icon,
23702
+ name,
23703
+ badge,
23704
+ to,
23705
+ navigate,
23706
+ className,
23707
+ onClick,
23708
+ style
23709
+ }) {
23710
+ return /* @__PURE__ */ jsx(
23711
+ MenuItem,
23712
+ {
23713
+ icon,
23714
+ name,
23715
+ badge,
23716
+ to,
23717
+ navigate,
23718
+ onClick,
23719
+ style,
23720
+ className
23721
+ }
23722
+ );
23723
+ }
23724
+ function ReviewReplyMenu({
23725
+ open,
23726
+ setOpen,
23727
+ canEdit,
23728
+ canDelete,
23729
+ canReport,
23730
+ onEdit,
23731
+ onDelete,
23732
+ onReport
23733
+ }) {
23734
+ const ref = useRef(null);
23735
+ useClickOutside(ref, () => setOpen(false));
23736
+ const items = [];
23737
+ if (canEdit) {
23738
+ items.push({
23739
+ type: "item",
23740
+ icon: /* @__PURE__ */ jsx(BiEdit, {}),
23741
+ name: "Edit Reply",
23742
+ component: ReviewReplyMenuItem,
23743
+ onClick: () => {
23744
+ setOpen(false);
23745
+ onEdit?.();
23746
+ },
23747
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800"
23748
+ });
23749
+ }
23750
+ if (canDelete) {
23751
+ items.push({
23752
+ type: "item",
23753
+ icon: /* @__PURE__ */ jsx(BiTrash, {}),
23754
+ name: "Delete Reply",
23755
+ component: ReviewReplyMenuItem,
23756
+ onClick: () => {
23757
+ setOpen(false);
23758
+ onDelete?.();
23759
+ },
23760
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm text-red-500 hover:bg-gray-100 dark:hover:bg-neutral-800"
23761
+ });
23762
+ }
23763
+ if (canReport) {
23764
+ items.push({
23765
+ type: "item",
23766
+ icon: /* @__PURE__ */ jsx(BiFlag, {}),
23767
+ name: "Report Reply",
23768
+ component: ReviewReplyMenuItem,
23769
+ onClick: () => {
23770
+ setOpen(false);
23771
+ onReport?.();
23772
+ },
23773
+ className: "flex w-full items-center gap-2 px-4 py-3 text-sm hover:bg-gray-100 dark:hover:bg-neutral-800"
23774
+ });
23775
+ }
23776
+ if (!items.length) {
23777
+ return null;
23778
+ }
23779
+ return /* @__PURE__ */ jsxs("div", { ref, className: "relative", children: [
23780
+ /* @__PURE__ */ jsx(
23781
+ "button",
23782
+ {
23783
+ type: "button",
23784
+ onClick: () => setOpen(!open),
23785
+ className: "text-gray-500 transition-colors hover:text-gray-900 dark:hover:text-gray-100",
23786
+ "aria-label": "Review reply options",
23787
+ children: /* @__PURE__ */ jsx(BiDotsVerticalRounded, { size: 18 })
23788
+ }
23789
+ ),
23790
+ /* @__PURE__ */ jsx(Transition.TransitionDropdown, { visibility: open, children: /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-full z-50 mt-2 min-w-[180px] overflow-hidden rounded-xl border border-gray-200 bg-white shadow-xl dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsx(Menu, { items }) }) })
23791
+ ] });
23792
+ }
23793
+ var ReviewReplyMenu_default = ReviewReplyMenu;
23794
+ function ReviewReplyItem({
23795
+ reply,
23796
+ parentReview,
23797
+ config,
23798
+ components,
23799
+ onEditReviewReply,
23800
+ onDeleteReviewReply,
23801
+ onReportReviewReply
23802
+ }) {
23803
+ const [menuOpen, setMenuOpen] = useState(false);
23804
+ const HeaderComponent = components?.ReplyHeader ?? ReviewReplyHeader_default;
23805
+ const ContentComponent = components?.ReplyContent ?? ReviewReplyContent_default;
23806
+ const MenuComponent = components?.ReplyMenu ?? ReviewReplyMenu_default;
23807
+ const canEdit = canEditReviewReply(reply);
23808
+ const canDelete = canDeleteReviewReply(reply);
23809
+ const canReport = canReportReviewReply(reply);
23810
+ return /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-gray-200 bg-gray-50 p-4 dark:border-neutral-800 dark:bg-neutral-950", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
23811
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
23812
+ /* @__PURE__ */ jsx(
23813
+ HeaderComponent,
23814
+ {
23815
+ reply,
23816
+ parentReview,
23817
+ config
23818
+ }
23819
+ ),
23820
+ /* @__PURE__ */ jsx(
23821
+ MenuComponent,
23822
+ {
23823
+ reply,
23824
+ parentReview,
23825
+ open: menuOpen,
23826
+ setOpen: setMenuOpen,
23827
+ canEdit,
23828
+ canDelete,
23829
+ canReport,
23830
+ onEdit: () => onEditReviewReply?.(reply, parentReview),
23831
+ onDelete: () => onDeleteReviewReply?.(reply, parentReview),
23832
+ onReport: () => onReportReviewReply?.(reply, parentReview)
23833
+ }
23834
+ )
23835
+ ] }),
23836
+ /* @__PURE__ */ jsx(ContentComponent, { reply, parentReview })
23837
+ ] }) });
23838
+ }
23839
+ var ReviewReplyItem_default = ReviewReplyItem;
23840
+ function ReviewReplyList({
23841
+ review,
23842
+ replies,
23843
+ config,
23844
+ components,
23845
+ onEditReviewReply,
23846
+ onDeleteReviewReply,
23847
+ onReportReviewReply
23848
+ }) {
23849
+ const ReplyItemComponent = components?.ReplyItem ?? ReviewReplyItem_default;
23850
+ if (!config.allowReplies || !replies.length) {
23851
+ return null;
23852
+ }
23853
+ return /* @__PURE__ */ jsx("div", { className: "ml-6 border-l border-gray-200 pl-4 dark:border-neutral-800", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: replies.map((reply) => /* @__PURE__ */ jsx(
23854
+ ReplyItemComponent,
23855
+ {
23856
+ reply,
23857
+ parentReview: review,
23858
+ config,
23859
+ components,
23860
+ onEditReviewReply,
23861
+ onDeleteReviewReply,
23862
+ onReportReviewReply
23863
+ },
23864
+ reply.id
23865
+ )) }) });
23866
+ }
23867
+ var ReviewReplyList_default = ReviewReplyList;
23868
+ function ReviewItem({
23869
+ review,
23870
+ config,
23871
+ components,
23872
+ onEditReview,
23873
+ onDeleteReview,
23874
+ onReportReview,
23875
+ onReplyToReview,
23876
+ onEditReviewReply,
23877
+ onDeleteReviewReply,
23878
+ onReportReviewReply
23879
+ }) {
23880
+ const [menuOpen, setMenuOpen] = useState(false);
23881
+ const HeaderComponent = components?.Header ?? ReviewHeader_default;
23882
+ const ContentComponent = components?.Content ?? ReviewContent_default;
23883
+ const RatingComponent = components?.Rating ?? ReviewRating_default;
23884
+ const RecommendationComponent = components?.Recommendation ?? ReviewRecommendation_default;
23885
+ const MenuComponent = components?.Menu ?? ReviewMenu_default;
23886
+ const ActionsComponent = components?.Actions ?? ReviewActions_default;
23887
+ const ReplyListComponent = components?.ReplyList ?? ReviewReplyList_default;
23888
+ const replies = review.replies ?? [];
23889
+ const canEdit = canEditReview(review);
23890
+ const canDelete = canDeleteReview(review);
23891
+ const canReport = canReportReview(review);
23892
+ const canReply = config.allowReplies && canReplyToReview(review) && replies.length < config.maxRepliesPerReview;
23893
+ return /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-gray-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
23894
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
23895
+ /* @__PURE__ */ jsx(HeaderComponent, { review, config }),
23896
+ /* @__PURE__ */ jsx(
23897
+ MenuComponent,
23898
+ {
23899
+ review,
23900
+ open: menuOpen,
23901
+ setOpen: setMenuOpen,
23902
+ canEdit,
23903
+ canDelete,
23904
+ canReport,
23905
+ canReply,
23906
+ onEdit: () => onEditReview?.(review),
23907
+ onDelete: () => onDeleteReview?.(review),
23908
+ onReport: () => onReportReview?.(review),
23909
+ onReply: () => onReplyToReview?.(review)
23910
+ }
23911
+ )
23912
+ ] }),
23913
+ /* @__PURE__ */ jsx(ContentComponent, { review }),
23914
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
23915
+ /* @__PURE__ */ jsx(RatingComponent, { rating: review.rating, maxRating: config.maxRating }),
23916
+ config.allowRecommendation && /* @__PURE__ */ jsx(RecommendationComponent, { isRecommended: review.isRecommended })
23917
+ ] }),
23918
+ /* @__PURE__ */ jsx(
23919
+ ActionsComponent,
23920
+ {
23921
+ review,
23922
+ canReply,
23923
+ onReply: () => onReplyToReview?.(review)
23924
+ }
23925
+ ),
23926
+ /* @__PURE__ */ jsx(
23927
+ ReplyListComponent,
23928
+ {
23929
+ review,
23930
+ replies,
23931
+ config,
23932
+ components,
23933
+ onEditReviewReply,
23934
+ onDeleteReviewReply,
23935
+ onReportReviewReply
23936
+ }
23937
+ )
23938
+ ] }) });
23939
+ }
23940
+ var ReviewItem_default = ReviewItem;
23941
+ function ReviewEmptyState({
23942
+ title = "No reviews yet",
23943
+ text = "There are no reviews to show."
23944
+ }) {
23945
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-gray-300 bg-white p-8 text-center dark:border-neutral-800 dark:bg-neutral-900", children: [
23946
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: title }),
23947
+ text && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-gray-500 dark:text-gray-400", children: text })
23948
+ ] });
23949
+ }
23950
+ var ReviewEmptyState_default = ReviewEmptyState;
23951
+ function ReviewList({
23952
+ reviews,
23953
+ config,
23954
+ components,
23955
+ onEditReview,
23956
+ onDeleteReview,
23957
+ onReportReview,
23958
+ onReplyToReview,
23959
+ onEditReviewReply,
23960
+ onDeleteReviewReply,
23961
+ onReportReviewReply
23962
+ }) {
23963
+ const ItemComponent = components?.Item ?? ReviewItem_default;
23964
+ const EmptyStateComponent = components?.EmptyState ?? ReviewEmptyState_default;
23965
+ if (!reviews.length) {
23966
+ return /* @__PURE__ */ jsx(
23967
+ EmptyStateComponent,
23968
+ {
23969
+ title: config.emptyTitle,
23970
+ text: config.emptyText
23971
+ }
23972
+ );
23973
+ }
23974
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-5", children: reviews.map((review) => /* @__PURE__ */ jsx(
23975
+ ItemComponent,
23976
+ {
23977
+ review,
23978
+ config,
23979
+ components,
23980
+ onEditReview,
23981
+ onDeleteReview,
23982
+ onReportReview,
23983
+ onReplyToReview,
23984
+ onEditReviewReply,
23985
+ onDeleteReviewReply,
23986
+ onReportReviewReply
23987
+ },
23988
+ review.id
23989
+ )) });
23990
+ }
23991
+ var ReviewList_default = ReviewList;
23992
+
23993
+ // src/compositions/review-thread/constants/review-thread.constants.ts
23994
+ var DEFAULT_REVIEW_THREAD_CONFIG = {
23995
+ reviewsPerPage: 10,
23996
+ dateFormat: "relative",
23997
+ minRating: 1,
23998
+ maxRating: 5,
23999
+ minContentLength: 8,
24000
+ maxContentLength: 2e3,
24001
+ allowRecommendation: true,
24002
+ showMyReviewPanel: true,
24003
+ showMyReviewInList: true,
24004
+ allowReplies: true,
24005
+ maxRepliesPerReview: 1,
24006
+ ownerReplyLabel: "Owner",
24007
+ emptyTitle: "No reviews yet",
24008
+ emptyText: "There are no reviews to show."
24009
+ };
24010
+ function isReviewEntity(value) {
24011
+ return Boolean(value && "rating" in value);
24012
+ }
24013
+ function updateReviewEverywhere(review, updater) {
24014
+ return updater(review);
24015
+ }
24016
+ function useReviewThreadState({
24017
+ targetId,
24018
+ dataSource,
24019
+ config,
24020
+ shouldLoadMyReview = true,
24021
+ loading = false,
24022
+ updatedReview,
24023
+ deletedReview,
24024
+ updatedReviewReply,
24025
+ deletedReviewReply,
24026
+ onReviewCreated,
24027
+ onReviewUpdated,
24028
+ onReviewDeleted
24029
+ }) {
24030
+ const [reviews, setReviews] = useState([]);
24031
+ const [myReview, setMyReview] = useState(null);
24032
+ const [isLoadingReviews, setIsLoadingReviews] = useState(true);
24033
+ const [isLoadingMyReview, setIsLoadingMyReview] = useState(
24034
+ Boolean(dataSource.getMyReview && shouldLoadMyReview)
24035
+ );
24036
+ const [isCreatingReview, setIsCreatingReview] = useState(false);
24037
+ const [isUpdatingReview, setIsUpdatingReview] = useState(false);
24038
+ const [isDeletingReview, setIsDeletingReview] = useState(false);
24039
+ const [isCreatingReviewReply, setIsCreatingReviewReply] = useState(false);
24040
+ const [isUpdatingReviewReply, setIsUpdatingReviewReply] = useState(false);
24041
+ const [isDeletingReviewReply, setIsDeletingReviewReply] = useState(false);
24042
+ const [reviewsError, setReviewsError] = useState(null);
24043
+ const [myReviewError, setMyReviewError] = useState(null);
24044
+ const error = reviewsError ?? myReviewError;
24045
+ const visibleReviews = useMemo(() => {
24046
+ if (config.showMyReviewInList || !myReview) {
24047
+ return reviews;
24048
+ }
24049
+ return reviews.filter((review) => review.id !== myReview.id);
24050
+ }, [config.showMyReviewInList, myReview, reviews]);
24051
+ const applyReview = useCallback((review) => {
24052
+ setReviews((prev) => upsertReview(prev, review));
24053
+ setMyReview((prev) => {
24054
+ if (!prev || prev.id !== review.id) {
24055
+ return prev;
24056
+ }
24057
+ return review;
24058
+ });
24059
+ }, []);
24060
+ const applyReviewUpdater = useCallback(
24061
+ (reviewId, updater) => {
24062
+ setReviews((prev) => updateReview(prev, reviewId, updater));
24063
+ setMyReview((prev) => {
24064
+ if (!prev || prev.id !== reviewId) {
24065
+ return prev;
24066
+ }
24067
+ return updateReviewEverywhere(prev, updater);
24068
+ });
24069
+ },
24070
+ []
24071
+ );
24072
+ const removeReviewById = useCallback((reviewId) => {
24073
+ setReviews((prev) => removeReview(prev, reviewId));
24074
+ setMyReview((prev) => {
24075
+ if (!prev || prev.id !== reviewId) {
24076
+ return prev;
24077
+ }
24078
+ return null;
24079
+ });
24080
+ }, []);
24081
+ const loadReviews = useCallback(async () => {
24082
+ try {
24083
+ setIsLoadingReviews(true);
24084
+ setReviewsError(null);
24085
+ const result = await dataSource.getReviews({
24086
+ limit: config.reviewsPerPage
24087
+ });
24088
+ setReviews(result.items);
24089
+ } catch (error2) {
24090
+ setReviewsError(error2);
24091
+ } finally {
24092
+ setIsLoadingReviews(false);
24093
+ }
24094
+ }, [config.reviewsPerPage, dataSource, targetId]);
24095
+ const loadMyReview = useCallback(async () => {
24096
+ if (!dataSource.getMyReview || !shouldLoadMyReview) {
24097
+ setMyReview(null);
24098
+ setIsLoadingMyReview(false);
24099
+ setMyReviewError(null);
24100
+ return;
24101
+ }
24102
+ try {
24103
+ setIsLoadingMyReview(true);
24104
+ setMyReviewError(null);
24105
+ const result = await dataSource.getMyReview();
24106
+ setMyReview(result);
24107
+ } catch (error2) {
24108
+ setMyReview(null);
24109
+ setMyReviewError(error2);
24110
+ } finally {
24111
+ setIsLoadingMyReview(false);
24112
+ }
24113
+ }, [dataSource, shouldLoadMyReview, targetId]);
24114
+ const reload = useCallback(async () => {
24115
+ await Promise.all([loadReviews(), loadMyReview()]);
24116
+ }, [loadReviews, loadMyReview]);
24117
+ const createReview = useCallback(
24118
+ async (values) => {
24119
+ try {
24120
+ setIsCreatingReview(true);
24121
+ const review = await dataSource.createReview({
24122
+ content: values.content,
24123
+ rating: values.rating,
24124
+ isRecommended: values.isRecommended
24125
+ });
24126
+ setMyReview(review);
24127
+ setReviews((prev) => prependReview(prev, review));
24128
+ onReviewCreated?.(review);
24129
+ return review;
24130
+ } finally {
24131
+ setIsCreatingReview(false);
24132
+ }
24133
+ },
24134
+ [dataSource, onReviewCreated]
24135
+ );
24136
+ const updateReview2 = useCallback(
24137
+ async (review, values) => {
24138
+ try {
24139
+ setIsUpdatingReview(true);
24140
+ const updated = await dataSource.updateReview({
24141
+ id: review.id,
24142
+ content: values.content,
24143
+ rating: values.rating,
24144
+ isRecommended: values.isRecommended
24145
+ });
24146
+ setMyReview((prev) => {
24147
+ if (!prev || prev.id !== updated.id) {
24148
+ return prev;
24149
+ }
24150
+ return updated;
24151
+ });
24152
+ setReviews((prev) => upsertReview(prev, updated));
24153
+ onReviewUpdated?.(updated);
24154
+ return updated;
24155
+ } finally {
24156
+ setIsUpdatingReview(false);
24157
+ }
24158
+ },
24159
+ [dataSource, onReviewUpdated]
24160
+ );
24161
+ const deleteReview = useCallback(
24162
+ async (review) => {
24163
+ try {
24164
+ setIsDeletingReview(true);
24165
+ await dataSource.deleteReview(review.id);
24166
+ removeReviewById(review.id);
24167
+ onReviewDeleted?.(review);
24168
+ } finally {
24169
+ setIsDeletingReview(false);
24170
+ }
24171
+ },
24172
+ [dataSource, onReviewDeleted, removeReviewById]
24173
+ );
24174
+ const createReviewReply = useCallback(
24175
+ async (input) => {
24176
+ if (!dataSource.createReviewReply) {
24177
+ throw new Error("createReviewReply is not implemented by dataSource.");
24178
+ }
24179
+ try {
24180
+ setIsCreatingReviewReply(true);
24181
+ const result = await dataSource.createReviewReply(input);
24182
+ if (isReviewEntity(result)) {
24183
+ applyReview(result);
24184
+ } else {
24185
+ applyReviewUpdater(
24186
+ input.reviewId,
24187
+ (review) => addReviewReply(review, result, config.maxRepliesPerReview)
24188
+ );
24189
+ }
24190
+ return result;
24191
+ } finally {
24192
+ setIsCreatingReviewReply(false);
24193
+ }
24194
+ },
24195
+ [
24196
+ applyReview,
24197
+ applyReviewUpdater,
24198
+ config.maxRepliesPerReview,
24199
+ dataSource
24200
+ ]
24201
+ );
24202
+ const updateReviewReply2 = useCallback(
24203
+ async (input) => {
24204
+ if (!dataSource.updateReviewReply) {
24205
+ throw new Error("updateReviewReply is not implemented by dataSource.");
24206
+ }
24207
+ try {
24208
+ setIsUpdatingReviewReply(true);
24209
+ const result = await dataSource.updateReviewReply(input);
24210
+ if (isReviewEntity(result)) {
24211
+ applyReview(result);
24212
+ } else {
24213
+ applyReviewUpdater(
24214
+ input.reviewId,
24215
+ (review) => replaceReviewReply(review, result)
24216
+ );
24217
+ }
24218
+ return result;
24219
+ } finally {
24220
+ setIsUpdatingReviewReply(false);
24221
+ }
24222
+ },
24223
+ [applyReview, applyReviewUpdater, dataSource]
24224
+ );
24225
+ const deleteReviewReply = useCallback(
24226
+ async (reviewId, replyId) => {
24227
+ if (!dataSource.deleteReviewReply) {
24228
+ throw new Error("deleteReviewReply is not implemented by dataSource.");
24229
+ }
24230
+ try {
24231
+ setIsDeletingReviewReply(true);
24232
+ const result = await dataSource.deleteReviewReply(reviewId, replyId);
24233
+ if (isReviewEntity(result)) {
24234
+ applyReview(result);
24235
+ } else {
24236
+ applyReviewUpdater(
24237
+ reviewId,
24238
+ (review) => removeReviewReply(review, replyId)
24239
+ );
24240
+ }
24241
+ return result;
24242
+ } finally {
24243
+ setIsDeletingReviewReply(false);
24244
+ }
24245
+ },
24246
+ [applyReview, applyReviewUpdater, dataSource]
24247
+ );
24248
+ useEffect(() => {
24249
+ let cancelled = false;
24250
+ async function run() {
24251
+ try {
24252
+ setIsLoadingReviews(true);
24253
+ setReviewsError(null);
24254
+ const result = await dataSource.getReviews({
24255
+ limit: config.reviewsPerPage
24256
+ });
24257
+ if (!cancelled) {
24258
+ setReviews(result.items);
24259
+ }
24260
+ } catch (error2) {
24261
+ if (!cancelled) {
24262
+ setReviewsError(error2);
24263
+ }
24264
+ } finally {
24265
+ if (!cancelled) {
24266
+ setIsLoadingReviews(false);
24267
+ }
24268
+ }
24269
+ }
24270
+ void run();
24271
+ return () => {
24272
+ cancelled = true;
24273
+ };
24274
+ }, [config.reviewsPerPage, dataSource, targetId]);
24275
+ useEffect(() => {
24276
+ let cancelled = false;
24277
+ async function run() {
24278
+ if (!dataSource.getMyReview || !shouldLoadMyReview) {
24279
+ setMyReview(null);
24280
+ setMyReviewError(null);
24281
+ setIsLoadingMyReview(false);
24282
+ return;
24283
+ }
24284
+ try {
24285
+ setIsLoadingMyReview(true);
24286
+ setMyReviewError(null);
24287
+ const result = await dataSource.getMyReview();
24288
+ if (!cancelled) {
24289
+ setMyReview(result);
24290
+ }
24291
+ } catch (error2) {
24292
+ if (!cancelled) {
24293
+ setMyReview(null);
24294
+ setMyReviewError(error2);
24295
+ }
24296
+ } finally {
24297
+ if (!cancelled) {
24298
+ setIsLoadingMyReview(false);
24299
+ }
24300
+ }
24301
+ }
24302
+ void run();
24303
+ return () => {
24304
+ cancelled = true;
24305
+ };
24306
+ }, [dataSource, shouldLoadMyReview, targetId]);
24307
+ useEffect(() => {
24308
+ if (!updatedReview) {
24309
+ return;
24310
+ }
24311
+ applyReview(updatedReview);
24312
+ }, [applyReview, updatedReview]);
24313
+ useEffect(() => {
24314
+ if (!deletedReview) {
24315
+ return;
24316
+ }
24317
+ removeReviewById(deletedReview.id);
24318
+ }, [deletedReview, removeReviewById]);
24319
+ useEffect(() => {
24320
+ if (!updatedReviewReply) {
24321
+ return;
24322
+ }
24323
+ if (updatedReviewReply.review) {
24324
+ applyReview(updatedReviewReply.review);
24325
+ return;
24326
+ }
24327
+ if (!updatedReviewReply.reply) {
24328
+ return;
24329
+ }
24330
+ applyReviewUpdater(updatedReviewReply.reviewId, (review) => {
24331
+ if (hasReviewReply(review, updatedReviewReply.reply.id)) {
24332
+ return replaceReviewReply(review, updatedReviewReply.reply);
24333
+ }
24334
+ return addReviewReply(
24335
+ review,
24336
+ updatedReviewReply.reply,
24337
+ config.maxRepliesPerReview
24338
+ );
24339
+ });
24340
+ }, [
24341
+ applyReview,
24342
+ applyReviewUpdater,
24343
+ config.maxRepliesPerReview,
24344
+ updatedReviewReply
24345
+ ]);
24346
+ useEffect(() => {
24347
+ if (!deletedReviewReply) {
24348
+ return;
24349
+ }
24350
+ if (deletedReviewReply.review) {
24351
+ applyReview(deletedReviewReply.review);
24352
+ return;
24353
+ }
24354
+ applyReviewUpdater(
24355
+ deletedReviewReply.reviewId,
24356
+ (review) => removeReviewReply(review, deletedReviewReply.replyId)
24357
+ );
24358
+ }, [applyReview, applyReviewUpdater, deletedReviewReply]);
24359
+ return {
24360
+ reviews,
24361
+ visibleReviews,
24362
+ myReview,
24363
+ isLoadingReviews,
24364
+ isLoadingMyReview,
24365
+ isInitialLoading: loading || isLoadingReviews || isLoadingMyReview,
24366
+ isCreatingReview,
24367
+ isUpdatingReview,
24368
+ isDeletingReview,
24369
+ isCreatingReviewReply,
24370
+ isUpdatingReviewReply,
24371
+ isDeletingReviewReply,
24372
+ reviewsError,
24373
+ myReviewError,
24374
+ error,
24375
+ setReviews,
24376
+ setMyReview,
24377
+ loadReviews,
24378
+ loadMyReview,
24379
+ reload,
24380
+ createReview,
24381
+ updateReview: updateReview2,
24382
+ deleteReview,
24383
+ createReviewReply,
24384
+ updateReviewReply: updateReviewReply2,
24385
+ deleteReviewReply,
24386
+ applyReview,
24387
+ removeReviewById
24388
+ };
24389
+ }
24390
+ function ReviewThread({
24391
+ targetId,
24392
+ currentUser,
24393
+ dataSource,
24394
+ loading = false,
24395
+ disabled = false,
24396
+ config,
24397
+ components,
24398
+ updatedReview,
24399
+ deletedReview,
24400
+ updatedReviewReply,
24401
+ deletedReviewReply,
24402
+ onLoginClick,
24403
+ onEditReview,
24404
+ onDeleteReview,
24405
+ onReportReview,
24406
+ onReplyToReview,
24407
+ onEditReviewReply,
24408
+ onDeleteReviewReply,
24409
+ onReportReviewReply,
24410
+ onReviewCreated,
24411
+ onReviewUpdated,
24412
+ onReviewDeleted
24413
+ }) {
24414
+ const resolvedConfig = {
24415
+ ...DEFAULT_REVIEW_THREAD_CONFIG,
24416
+ ...config
24417
+ };
24418
+ const reviewState = useReviewThreadState({
24419
+ targetId,
24420
+ dataSource,
24421
+ config: resolvedConfig,
24422
+ shouldLoadMyReview: Boolean(currentUser),
24423
+ loading,
24424
+ updatedReview,
24425
+ deletedReview,
24426
+ updatedReviewReply,
24427
+ deletedReviewReply,
24428
+ onReviewCreated,
24429
+ onReviewUpdated,
24430
+ onReviewDeleted
24431
+ });
24432
+ function handleEditReview(review) {
24433
+ onEditReview?.(review);
24434
+ }
24435
+ function handleDeleteReview(review) {
24436
+ if (onDeleteReview) {
24437
+ onDeleteReview(review);
24438
+ return;
24439
+ }
24440
+ void reviewState.deleteReview(review);
24441
+ }
24442
+ function handleReportReview(review) {
24443
+ onReportReview?.(review);
24444
+ }
24445
+ function handleReplyToReview(review) {
24446
+ onReplyToReview?.(review);
24447
+ }
24448
+ function handleEditReviewReply(reply, parentReview) {
24449
+ onEditReviewReply?.(reply, parentReview);
24450
+ }
24451
+ function handleDeleteReviewReply(reply, parentReview) {
24452
+ onDeleteReviewReply?.(reply, parentReview);
24453
+ }
24454
+ function handleReportReviewReply(reply, parentReview) {
24455
+ onReportReviewReply?.(reply, parentReview);
24456
+ }
24457
+ if (reviewState.isInitialLoading) {
24458
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
24459
+ resolvedConfig.showMyReviewPanel && /* @__PURE__ */ jsx("div", { className: "h-40 animate-pulse rounded-xl bg-gray-100 dark:bg-neutral-900" }),
24460
+ /* @__PURE__ */ jsx("div", { className: "h-36 animate-pulse rounded-xl bg-gray-100 dark:bg-neutral-900" }),
24461
+ /* @__PURE__ */ jsx("div", { className: "h-36 animate-pulse rounded-xl bg-gray-100 dark:bg-neutral-900" })
24462
+ ] });
24463
+ }
24464
+ if (reviewState.error && !reviewState.reviews.length) {
24465
+ return /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 p-5 dark:border-red-500/20 dark:bg-red-500/10", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
24466
+ /* @__PURE__ */ jsxs("div", { children: [
24467
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-red-700 dark:text-red-400", children: "Failed to load reviews" }),
24468
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-red-600/80 dark:text-red-300/80", children: "Something went wrong while loading the review thread." })
24469
+ ] }),
24470
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
24471
+ Button_default,
24472
+ {
24473
+ text: "Retry",
24474
+ variant: "danger",
24475
+ appearance: "ghost",
24476
+ onClick: () => {
24477
+ void reviewState.reload();
24478
+ }
24479
+ }
24480
+ ) })
24481
+ ] }) });
24482
+ }
24483
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-8", children: [
24484
+ resolvedConfig.showMyReviewPanel && /* @__PURE__ */ jsx(
24485
+ MyReviewPanel_default,
24486
+ {
24487
+ currentUser,
24488
+ myReview: reviewState.myReview,
24489
+ loading: reviewState.isCreatingReview || reviewState.isUpdatingReview || reviewState.isDeletingReview,
24490
+ disabled,
24491
+ config: resolvedConfig,
24492
+ components,
24493
+ onLoginClick,
24494
+ onCreateReview: reviewState.createReview,
24495
+ onUpdateReview: reviewState.updateReview,
24496
+ onEditReview: handleEditReview,
24497
+ onDeleteReview: handleDeleteReview
24498
+ }
24499
+ ),
24500
+ /* @__PURE__ */ jsx(
24501
+ ReviewList_default,
24502
+ {
24503
+ reviews: reviewState.visibleReviews,
24504
+ config: resolvedConfig,
24505
+ components,
24506
+ onEditReview: handleEditReview,
24507
+ onDeleteReview: handleDeleteReview,
24508
+ onReportReview: handleReportReview,
24509
+ onReplyToReview: handleReplyToReview,
24510
+ onEditReviewReply: handleEditReviewReply,
24511
+ onDeleteReviewReply: handleDeleteReviewReply,
24512
+ onReportReviewReply: handleReportReviewReply
24513
+ }
24514
+ )
24515
+ ] });
24516
+ }
24517
+ var ReviewThread_default = ReviewThread;
22951
24518
  function GenericLayout({
22952
24519
  children,
22953
24520
  styles,
@@ -23064,6 +24631,6 @@ function ScrollToTop({
23064
24631
  }
23065
24632
  var ScrollToTop_default = ScrollToTop;
23066
24633
 
23067
- export { Accordion_default as Accordion, AreaPlot, AsyncComponentWrapper_default as AsyncComponentWrapper, Avatar, Backdrop_default as Backdrop, Badge, BarPlot, BaseChartDataSource, Block_default as Block, BlockGroup_default as BlockGroup, BoxNav_default as BoxNav, BoxNavItem_default as BoxNavItem, Brand_default as Brand, Breadcrumb, BreadcrumbItem_default as BreadcrumbItem, Button_default as Button, CHART_COLOR_PALETTE, CHART_DARK_THEME, CHART_DATA_MODES, CHART_DEFAULT_ACTIVE_DOT_RADIUS, CHART_DEFAULT_ANIMATION_DURATION, CHART_DEFAULT_BAR_RADIUS, CHART_DEFAULT_DOT_RADIUS, CHART_DEFAULT_HEIGHT, CHART_DEFAULT_MARGIN, CHART_DEFAULT_MAX_REALTIME_POINTS, CHART_DEFAULT_POLLING_INTERVAL, CHART_DEFAULT_STROKE_WIDTH, CHART_EMPTY_MESSAGE, CHART_ERROR_MESSAGE, CHART_LIGHT_THEME, CHART_LOADING_MESSAGE, CHART_STATUSES, CHART_STATUS_COLORS, CHART_VALUE_FORMATS, Caption, Card_default as Card, CardContent_default as CardContent, CardFooter_default as CardFooter, CardHeader_default as CardHeader, Chapter, Chart, ChartContainer, ChartContext, ChartEmptyState, ChartErrorState, ChartHeader, ChartLegend, ChartLoadingState, ChartPanel, ChartProvider, ChartToolbar, ChartTooltip, Checkbox_default as Checkbox, Chip, CloudinaryImage_default as CloudinaryImage, CloudinaryProvider, CloudinaryVideo_default as CloudinaryVideo, Code, CommentThread_default as CommentThread, ConfigBootstrap_default as ConfigBootstrap, Configurator, ConfiguratorError, Content, ContentArea_default as ContentArea, DEFAULT_CHART_THEME, DataView, DataViewTable_default as DataViewTable, DateSelector_default as DateSelector, DefaultLayout_default as DefaultLayout, Display, DocumentationPanel_default as DocumentationPanel, Drawer, DrawerToggler_default as DrawerToggler, EUIDevLayout_default as EUIDevLayout, EUIProvider, EnvErrorScreen_default as EnvErrorScreen, Flag, Flex, FlexCol_default as FlexCol, FlexRow_default as FlexRow, Footer, FooterNav_default as FooterNav, FooterNavGroup_default as FooterNavGroup, FooterNavItem, FooterNavItemContext, FooterNavItemTitle, Form, FormResponse_default as FormResponse, GaugePlot, GenericLayout_default as GenericLayout, GlowWrapper_default as GlowWrapper, Graph, GraphEdge, GraphNode, GraphRenderer, Grid_default as Grid, Header, HeaderNav_default as HeaderNav, HeaderNavGroup_default as HeaderNavGroup, HeaderNavItem, HeaderNavItemContext, HeaderNavItemTitle, HomeLayout_default as HomeLayout, Image2 as Image, ImageInput_default as ImageInput, InfiniteScrollTrigger_default as InfiniteScrollTrigger, Info_default as Info, Input, InputFile, InputLabel_default as InputLabel, InputList, InputListGroup, InputResponse_default as InputResponse, Label, Layout, Lead, LinePlot, Link, List_default as List, ListItem_default as ListItem, MarkdownEditor_default as MarkdownEditor, MarkdownProvider_default as MarkdownProvider, MarkdownTOC_default as MarkdownTOC, MarkdownViewer_default as MarkdownViewer, Menu, MenuGroup, MenuItem, MenuItemTitle, Modal_default as Modal, MotionSurface_default as MotionSurface, MultiImageInput_default as MultiImageInput, NumericRating_default as NumericRating, Overline, Paragraph, PiePlot, PollingChartDataSource, PriceTag, ProgressBar, ProgressBarRating_default as ProgressBarRating, Quote, Radio_default as Radio, RealtimeChartDataSource, RouteTab_default as RouteTab, RouteTabs_default as RouteTabs, ScatterPlot, ScrollToTop_default as ScrollToTop, Section, Select_default as Select, ShapeSwitch, ShowMore_default as ShowMore, Sidebar_default as Sidebar, SidebarLayout_default as SidebarLayout, SidemenuLayout_default as SidemenuLayout, Skeleton, Slider_default as Slider, Spinner_default as Spinner, StarRating_default as StarRating, StarRatingDistribution_default as StarRatingDistribution, StarRatingInput_default as StarRatingInput, StatPlot, StaticChartDataSource, Switch_default as Switch, TNDropdown, TNDropdownItem, TNDropdownTitle, TNGroup, Table_default as Table, Tag_default as Tag, Tags_default as Tags, TextArea_default as TextArea, ThemeContext, ThemeProvider, ThemeSwitch, TitleBanner, Toast, Tooltip6 as Tooltip, TopNav, Transition, TransitionAccordion_default as TransitionAccordion, TransitionBase_default as TransitionBase, TransitionDropdown_default as TransitionDropdown, TransitionFade_default as TransitionFade, TransitionFadeIn_default as TransitionFadeIn, TransitionScale_default as TransitionScale, TransitionSlide_default as TransitionSlide, Typography, UnderConstructionBanner, ValueBadge_default as ValueBadge, WorldMap, WorldMapCountryTable, YoutubeVideo_default as YoutubeVideoPlayer, addReplyToCache, applyReactionState, assertAbsoluteURL, buildURL, chartReducer, cn, createConfigurator, createForceLayout, createGridLayout, createInitialChartState, createTreeLayout, createURLResolver, decrementReplyCount, enumValues, euiToast, formatChartValue, formatCommentDate, formatConfigError, getAllowedOrigins, getBrowserHref, getBrowserOrigin, getBrowserRedirectURL, getCurrencySymbol, getLayout, getOptimisticDislikeState, getOptimisticLikeState, getSafeRedirect, incrementReplyCount, isMatch, isRenderFn, limitRealtimePoints, normalize, normalizeChartData, normalizeChartDataPoint, parseJson, parseJsonRecord, parseUrlMap, registerLayout, removeComment, removeCommentTreeFromCache, replaceRealtimePoints, resolveAppearanceStyles, resolveChartColor, resolveChartColors, resolveWithGlobal, sendToast, toConfiguratorError, updateComment, updateReplyCacheComment, useChartContext, useChartData, useChartPolling, useChartRealtime, useChartSeries, useChartTheme, useClickOutside, useCloudinaryConfig, useCurrentTheme_default as useCurrentTheme, useDrawer_default as useDrawer, useEUIConfig, useIsMobile_default as useIsMobile, useModal_default as useModal, useTheme_default as useTheme };
24634
+ export { Accordion_default as Accordion, AreaPlot, AsyncComponentWrapper_default as AsyncComponentWrapper, Avatar, Backdrop_default as Backdrop, Badge, BarPlot, BaseChartDataSource, Block_default as Block, BlockGroup_default as BlockGroup, BoxNav_default as BoxNav, BoxNavItem_default as BoxNavItem, Brand_default as Brand, Breadcrumb, BreadcrumbItem_default as BreadcrumbItem, Button_default as Button, CHART_COLOR_PALETTE, CHART_DARK_THEME, CHART_DATA_MODES, CHART_DEFAULT_ACTIVE_DOT_RADIUS, CHART_DEFAULT_ANIMATION_DURATION, CHART_DEFAULT_BAR_RADIUS, CHART_DEFAULT_DOT_RADIUS, CHART_DEFAULT_HEIGHT, CHART_DEFAULT_MARGIN, CHART_DEFAULT_MAX_REALTIME_POINTS, CHART_DEFAULT_POLLING_INTERVAL, CHART_DEFAULT_STROKE_WIDTH, CHART_EMPTY_MESSAGE, CHART_ERROR_MESSAGE, CHART_LIGHT_THEME, CHART_LOADING_MESSAGE, CHART_STATUSES, CHART_STATUS_COLORS, CHART_VALUE_FORMATS, Caption, Card_default as Card, CardContent_default as CardContent, CardFooter_default as CardFooter, CardHeader_default as CardHeader, Chapter, Chart, ChartContainer, ChartContext, ChartEmptyState, ChartErrorState, ChartHeader, ChartLegend, ChartLoadingState, ChartPanel, ChartProvider, ChartToolbar, ChartTooltip, Checkbox_default as Checkbox, Chip, CloudinaryImage_default as CloudinaryImage, CloudinaryProvider, CloudinaryVideo_default as CloudinaryVideo, Code, CommentThread_default as CommentThread, ConfigBootstrap_default as ConfigBootstrap, Configurator, ConfiguratorError, Content, ContentArea_default as ContentArea, DEFAULT_CHART_THEME, DEFAULT_REVIEW_THREAD_CONFIG, DataView, DataViewTable_default as DataViewTable, DateSelector_default as DateSelector, DefaultLayout_default as DefaultLayout, Display, DocumentationPanel_default as DocumentationPanel, Drawer, DrawerToggler_default as DrawerToggler, EUIDevLayout_default as EUIDevLayout, EUIProvider, EnvErrorScreen_default as EnvErrorScreen, Flag, Flex, FlexCol_default as FlexCol, FlexRow_default as FlexRow, Footer, FooterNav_default as FooterNav, FooterNavGroup_default as FooterNavGroup, FooterNavItem, FooterNavItemContext, FooterNavItemTitle, Form, FormResponse_default as FormResponse, GaugePlot, GenericLayout_default as GenericLayout, GlowWrapper_default as GlowWrapper, Graph, GraphEdge, GraphNode, GraphRenderer, Grid_default as Grid, Header, HeaderNav_default as HeaderNav, HeaderNavGroup_default as HeaderNavGroup, HeaderNavItem, HeaderNavItemContext, HeaderNavItemTitle, HomeLayout_default as HomeLayout, Image2 as Image, ImageInput_default as ImageInput, InfiniteScrollTrigger_default as InfiniteScrollTrigger, Info_default as Info, Input, InputFile, InputLabel_default as InputLabel, InputList, InputListGroup, InputResponse_default as InputResponse, Label, Layout, Lead, LinePlot, Link, List_default as List, ListItem_default as ListItem, MarkdownEditor_default as MarkdownEditor, MarkdownProvider_default as MarkdownProvider, MarkdownTOC_default as MarkdownTOC, MarkdownViewer_default as MarkdownViewer, Menu, MenuGroup, MenuItem, MenuItemTitle, Modal_default as Modal, MotionSurface_default as MotionSurface, MultiImageInput_default as MultiImageInput, NumericRating_default as NumericRating, Overline, Paragraph, PiePlot, PollingChartDataSource, PriceTag, ProgressBar, ProgressBarRating_default as ProgressBarRating, Quote, Radio_default as Radio, RealtimeChartDataSource, ReviewThread_default as ReviewThread, RouteTab_default as RouteTab, RouteTabs_default as RouteTabs, ScatterPlot, ScrollToTop_default as ScrollToTop, Section, Select_default as Select, ShapeSwitch, ShowMore_default as ShowMore, Sidebar_default as Sidebar, SidebarLayout_default as SidebarLayout, SidemenuLayout_default as SidemenuLayout, Skeleton, Slider_default as Slider, Spinner_default as Spinner, StarRating_default as StarRating, StarRatingDistribution_default as StarRatingDistribution, StarRatingInput_default as StarRatingInput, StatPlot, StaticChartDataSource, Switch_default as Switch, TNDropdown, TNDropdownItem, TNDropdownTitle, TNGroup, Table_default as Table, Tag_default as Tag, Tags_default as Tags, TextArea_default as TextArea, ThemeContext, ThemeProvider, ThemeSwitch, TitleBanner, Toast, Tooltip6 as Tooltip, TopNav, Transition, TransitionAccordion_default as TransitionAccordion, TransitionBase_default as TransitionBase, TransitionDropdown_default as TransitionDropdown, TransitionFade_default as TransitionFade, TransitionFadeIn_default as TransitionFadeIn, TransitionScale_default as TransitionScale, TransitionSlide_default as TransitionSlide, Typography, UnderConstructionBanner, ValueBadge_default as ValueBadge, WorldMap, WorldMapCountryTable, YoutubeVideo_default as YoutubeVideoPlayer, addReplyToCache, addReviewReply, appendReview, applyReactionState, assertAbsoluteURL, buildURL, canDeleteReview, canDeleteReviewReply, canEditReview, canEditReviewReply, canReplyToReview, canReportReview, canReportReviewReply, chartReducer, cn, createConfigurator, createForceLayout, createGridLayout, createInitialChartState, createTreeLayout, createURLResolver, decrementReplyCount, enumValues, euiToast, findReview, formatChartValue, formatCommentDate, formatConfigError, formatReviewDate, getAllowedOrigins, getBrowserHref, getBrowserOrigin, getBrowserRedirectURL, getCurrencySymbol, getLayout, getOptimisticDislikeState, getOptimisticLikeState, getSafeRedirect, hasReviewReply, incrementReplyCount, isMatch, isRenderFn, limitRealtimePoints, normalize, normalizeChartData, normalizeChartDataPoint, normalizeReview, normalizeReviewAuthor, normalizeReviewReply, parseJson, parseJsonRecord, parseUrlMap, prependReview, registerLayout, removeComment, removeCommentTreeFromCache, removeReview, removeReviewReply, replaceRealtimePoints, replaceReview, replaceReviewReply, resolveAppearanceStyles, resolveChartColor, resolveChartColors, resolveWithGlobal, sendToast, toConfiguratorError, updateComment, updateReplyCacheComment, updateReview, updateReviewReply, upsertReview, useChartContext, useChartData, useChartPolling, useChartRealtime, useChartSeries, useChartTheme, useClickOutside, useCloudinaryConfig, useCurrentTheme_default as useCurrentTheme, useDrawer_default as useDrawer, useEUIConfig, useIsMobile_default as useIsMobile, useModal_default as useModal, useReviewThreadState, useTheme_default as useTheme };
23068
24635
  //# sourceMappingURL=index.mjs.map
23069
24636
  //# sourceMappingURL=index.mjs.map