@fluid-app/portal-sdk 0.1.492 → 0.1.494

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/{AnnouncementWidget-CNP37JUB.cjs → AnnouncementWidget--nRHRrQH.cjs} +3 -3
  2. package/dist/{AnnouncementWidget-93a322Pl.mjs → AnnouncementWidget-BND76Ojg.mjs} +2 -2
  3. package/dist/{AnnouncementWidget-93a322Pl.mjs.map → AnnouncementWidget-BND76Ojg.mjs.map} +1 -1
  4. package/dist/{AnnouncementWidget-BIFJ7E6o.cjs → AnnouncementWidget-Dh6nKAqT.cjs} +2 -2
  5. package/dist/{AnnouncementWidget-BIFJ7E6o.cjs.map → AnnouncementWidget-Dh6nKAqT.cjs.map} +1 -1
  6. package/dist/{CarouselWidget-fft3Aibh.cjs → CarouselWidget-BETNqs_K.cjs} +3 -3
  7. package/dist/{CarouselWidget-fft3Aibh.cjs.map → CarouselWidget-BETNqs_K.cjs.map} +1 -1
  8. package/dist/{CarouselWidget-COavwXvx.mjs → CarouselWidget-CU1oj0q4.mjs} +3 -3
  9. package/dist/{CarouselWidget-COavwXvx.mjs.map → CarouselWidget-CU1oj0q4.mjs.map} +1 -1
  10. package/dist/{CarouselWidget-DDKKVEan.cjs → CarouselWidget-D3BODbpO.cjs} +3 -3
  11. package/dist/{CatchUpWidget-C3HdLA5t.mjs → CatchUpWidget-BtwG2-JD.mjs} +2 -2
  12. package/dist/{CatchUpWidget-BNEEQNcr.mjs → CatchUpWidget-CLwHp30X.mjs} +5 -4
  13. package/dist/CatchUpWidget-CLwHp30X.mjs.map +1 -0
  14. package/dist/{CatchUpWidget-G4txAfv3.cjs → CatchUpWidget-CqAHpCJP.cjs} +5 -4
  15. package/dist/CatchUpWidget-CqAHpCJP.cjs.map +1 -0
  16. package/dist/{CatchUpWidget-g9GtsvCy.cjs → CatchUpWidget-ak-oFdKY.cjs} +2 -2
  17. package/dist/{FluidProvider-DxwbLpfX.mjs → FluidProvider-BRgNyDk3.mjs} +3 -3
  18. package/dist/{FluidProvider-DxwbLpfX.mjs.map → FluidProvider-BRgNyDk3.mjs.map} +1 -1
  19. package/dist/{FluidProvider-B7bYw1AY.cjs → FluidProvider-XONLsJbE.cjs} +3 -3
  20. package/dist/{FluidProvider-B7bYw1AY.cjs.map → FluidProvider-XONLsJbE.cjs.map} +1 -1
  21. package/dist/{ImageWidget-B3IlWnKJ.cjs → ImageWidget-CksrA9rH.cjs} +2 -2
  22. package/dist/{ImageWidget-B3IlWnKJ.cjs.map → ImageWidget-CksrA9rH.cjs.map} +1 -1
  23. package/dist/{ImageWidget-DiWlWvKm.cjs → ImageWidget-DmO84AYo.cjs} +3 -3
  24. package/dist/{ImageWidget-CovwH8bp.mjs → ImageWidget-I8F34YlI.mjs} +2 -2
  25. package/dist/{ImageWidget-CovwH8bp.mjs.map → ImageWidget-I8F34YlI.mjs.map} +1 -1
  26. package/dist/{LinkWidget-StpP6gPq.mjs → LinkWidget-Dg0tHfgD.mjs} +2 -2
  27. package/dist/{LinkWidget-StpP6gPq.mjs.map → LinkWidget-Dg0tHfgD.mjs.map} +1 -1
  28. package/dist/{LinkWidget-BTIsGyc5.cjs → LinkWidget-Dvp6-Dow.cjs} +2 -2
  29. package/dist/{LinkWidget-BTIsGyc5.cjs.map → LinkWidget-Dvp6-Dow.cjs.map} +1 -1
  30. package/dist/{LinkWidget-ZVFlL178.cjs → LinkWidget-N6yz6w-U.cjs} +3 -3
  31. package/dist/{ListWidget-ddhJLwxZ.mjs → ListWidget-BAS3SGpD.mjs} +3 -3
  32. package/dist/{ListWidget-ddhJLwxZ.mjs.map → ListWidget-BAS3SGpD.mjs.map} +1 -1
  33. package/dist/{ListWidget-6TkLyp00.cjs → ListWidget-CH-zz3sb.cjs} +3 -3
  34. package/dist/{ListWidget-6TkLyp00.cjs.map → ListWidget-CH-zz3sb.cjs.map} +1 -1
  35. package/dist/{ListWidget-BNAED5xZ.cjs → ListWidget-vG31UVVS.cjs} +3 -3
  36. package/dist/{MessagingScreen-CZje-9-C.mjs → MessagingScreen-B8--eInM.mjs} +19 -19
  37. package/dist/{MessagingScreen-DDVflwCT.cjs → MessagingScreen-D2oC8zGg.cjs} +19 -19
  38. package/dist/{MessagingScreen-Q0BSmRuJ.mjs → MessagingScreen-DYjU5smt.mjs} +2 -2
  39. package/dist/{MessagingScreen-Q0BSmRuJ.mjs.map → MessagingScreen-DYjU5smt.mjs.map} +1 -1
  40. package/dist/{MessagingScreen-D7Yuy_Rn.cjs → MessagingScreen-gPqbIcFd.cjs} +2 -2
  41. package/dist/{MessagingScreen-D7Yuy_Rn.cjs.map → MessagingScreen-gPqbIcFd.cjs.map} +1 -1
  42. package/dist/{NestedWidget-orTqukJD.cjs → NestedWidget-B24yMkV4.cjs} +2 -2
  43. package/dist/{NestedWidget-orTqukJD.cjs.map → NestedWidget-B24yMkV4.cjs.map} +1 -1
  44. package/dist/{NestedWidget-DMhmCZT6.mjs → NestedWidget-D31rZhTR.mjs} +2 -2
  45. package/dist/{NestedWidget-DMhmCZT6.mjs.map → NestedWidget-D31rZhTR.mjs.map} +1 -1
  46. package/dist/{NestedWidget-BZZqukZw.cjs → NestedWidget-DqM5HGFl.cjs} +2 -2
  47. package/dist/{OrdersScreen-vAO6E8EM.cjs → OrdersScreen-BdLqCq1V.cjs} +19 -19
  48. package/dist/{OrdersScreen-CXxGN6RY.mjs → OrdersScreen-CHSqar4N.mjs} +3 -3
  49. package/dist/{OrdersScreen-CXxGN6RY.mjs.map → OrdersScreen-CHSqar4N.mjs.map} +1 -1
  50. package/dist/{OrdersScreen-DOBWnf_w.mjs → OrdersScreen-DRcdhc7y.mjs} +19 -19
  51. package/dist/{OrdersScreen-C0TzmZCl.cjs → OrdersScreen-Xs90dlpC.cjs} +3 -3
  52. package/dist/{OrdersScreen-C0TzmZCl.cjs.map → OrdersScreen-Xs90dlpC.cjs.map} +1 -1
  53. package/dist/{ProfileScreen-B9NHS4A_.cjs → ProfileScreen-BeaM28Qw.cjs} +20 -20
  54. package/dist/{ProfileScreen-DWFXnUUU.mjs → ProfileScreen-C-YfTr7l.mjs} +20 -20
  55. package/dist/{ProfileScreen-BGLpyuef.mjs → ProfileScreen-CpoLji_m.mjs} +3 -3
  56. package/dist/{ProfileScreen-BGLpyuef.mjs.map → ProfileScreen-CpoLji_m.mjs.map} +1 -1
  57. package/dist/{ProfileScreen-tq1DJ71b.cjs → ProfileScreen-DdCPrQUL.cjs} +3 -3
  58. package/dist/{ProfileScreen-tq1DJ71b.cjs.map → ProfileScreen-DdCPrQUL.cjs.map} +1 -1
  59. package/dist/{QuickLinksWidget-DIkDVuvE.mjs → QuickLinksWidget-BiEUvm_J.mjs} +2 -2
  60. package/dist/{QuickLinksWidget-DIkDVuvE.mjs.map → QuickLinksWidget-BiEUvm_J.mjs.map} +1 -1
  61. package/dist/{QuickLinksWidget-DDFtIKqs.cjs → QuickLinksWidget-CLBvaogv.cjs} +2 -2
  62. package/dist/{QuickLinksWidget-DDFtIKqs.cjs.map → QuickLinksWidget-CLBvaogv.cjs.map} +1 -1
  63. package/dist/{QuickLinksWidget-HvMQHOkz.cjs → QuickLinksWidget-DzAL_wuz.cjs} +3 -3
  64. package/dist/{QuickShareWidget-BNf1Un61.cjs → QuickShareWidget-B7mlqgW8.cjs} +2 -2
  65. package/dist/{QuickShareWidget-lysi8Dhh.mjs → QuickShareWidget-Dzpzis1d.mjs} +2 -2
  66. package/dist/{QuickShareWidget-lysi8Dhh.mjs.map → QuickShareWidget-Dzpzis1d.mjs.map} +1 -1
  67. package/dist/{QuickShareWidget-mxiy1zdd.cjs → QuickShareWidget-wxRcBUkf.cjs} +2 -2
  68. package/dist/{QuickShareWidget-mxiy1zdd.cjs.map → QuickShareWidget-wxRcBUkf.cjs.map} +1 -1
  69. package/dist/{RecentActivityWidget-DGtKC_9F.mjs → RecentActivityWidget-BzmV4G8e.mjs} +2 -2
  70. package/dist/{RecentActivityWidget-DGtKC_9F.mjs.map → RecentActivityWidget-BzmV4G8e.mjs.map} +1 -1
  71. package/dist/{RecentActivityWidget-DcgOzvHx.cjs → RecentActivityWidget-DQcy41-I.cjs} +2 -2
  72. package/dist/{RecentActivityWidget-Cr1G82Cd.cjs → RecentActivityWidget-zBOY0c_B.cjs} +2 -2
  73. package/dist/{RecentActivityWidget-Cr1G82Cd.cjs.map → RecentActivityWidget-zBOY0c_B.cjs.map} +1 -1
  74. package/dist/{ShopWidget-C5hjVwsY.cjs → ShopWidget-CCITGTSs.cjs} +2 -2
  75. package/dist/{ShopWidget-C5hjVwsY.cjs.map → ShopWidget-CCITGTSs.cjs.map} +1 -1
  76. package/dist/{ShopWidget-BYQKWyri.mjs → ShopWidget-D98tmUgG.mjs} +2 -2
  77. package/dist/{ShopWidget-B80w-Drk.mjs → ShopWidget-DHM86LM3.mjs} +2 -2
  78. package/dist/{ShopWidget-B80w-Drk.mjs.map → ShopWidget-DHM86LM3.mjs.map} +1 -1
  79. package/dist/{ShopWidget-CoOK6Ctd.cjs → ShopWidget-DXVsF1Jh.cjs} +2 -2
  80. package/dist/{SubscriptionsScreen-BwcpTAn5.mjs → SubscriptionsScreen-BOM_1txu.mjs} +20 -20
  81. package/dist/{SubscriptionsScreen-BEzmLp01.cjs → SubscriptionsScreen-DGIEnvLM.cjs} +20 -20
  82. package/dist/{SubscriptionsScreen-Cy7RtO5K.cjs → SubscriptionsScreen-DzBPA9H8.cjs} +4 -4
  83. package/dist/{SubscriptionsScreen-Cy7RtO5K.cjs.map → SubscriptionsScreen-DzBPA9H8.cjs.map} +1 -1
  84. package/dist/{SubscriptionsScreen-C7OOGlBt.mjs → SubscriptionsScreen-cAKZwpIu.mjs} +4 -4
  85. package/dist/{SubscriptionsScreen-C7OOGlBt.mjs.map → SubscriptionsScreen-cAKZwpIu.mjs.map} +1 -1
  86. package/dist/{TableWidget-lXrvBX6U.cjs → TableWidget-B8F_uQ92.cjs} +2 -2
  87. package/dist/{TableWidget-Bxwn3QYs.mjs → TableWidget-CDGdl71J.mjs} +2 -2
  88. package/dist/{TableWidget-Bxwn3QYs.mjs.map → TableWidget-CDGdl71J.mjs.map} +1 -1
  89. package/dist/{TableWidget-uoeYCPzf.cjs → TableWidget-DNjUA2Il.cjs} +2 -2
  90. package/dist/{TableWidget-uoeYCPzf.cjs.map → TableWidget-DNjUA2Il.cjs.map} +1 -1
  91. package/dist/{VideoWidget-D8FAjnvj.cjs → VideoWidget-UQQoRmwC.cjs} +3 -3
  92. package/dist/{VideoWidget-DQzYOcFF.mjs → VideoWidget-Wca2-So_.mjs} +2 -2
  93. package/dist/{VideoWidget-DQzYOcFF.mjs.map → VideoWidget-Wca2-So_.mjs.map} +1 -1
  94. package/dist/{VideoWidget-BhN4oTGG.cjs → VideoWidget-bf-gkCfx.cjs} +2 -2
  95. package/dist/{VideoWidget-BhN4oTGG.cjs.map → VideoWidget-bf-gkCfx.cjs.map} +1 -1
  96. package/dist/{WidgetInteractionContext-Bjy4P_YP.cjs → WidgetInteractionContext-D9dBJ-39.cjs} +5 -3
  97. package/dist/WidgetInteractionContext-D9dBJ-39.cjs.map +1 -0
  98. package/dist/{WidgetInteractionContext-Ba_G5sDP.mjs → WidgetInteractionContext-IsMo73Ka.mjs} +5 -3
  99. package/dist/WidgetInteractionContext-IsMo73Ka.mjs.map +1 -0
  100. package/dist/{build-widget-registry-DAOb4Muk.mjs → build-widget-registry-70KBtqiR.mjs} +27 -27
  101. package/dist/{build-widget-registry-DAOb4Muk.mjs.map → build-widget-registry-70KBtqiR.mjs.map} +1 -1
  102. package/dist/{build-widget-registry-BZeMOKCj.cjs → build-widget-registry-CWQ0YvEy.cjs} +27 -27
  103. package/dist/{build-widget-registry-BZeMOKCj.cjs.map → build-widget-registry-CWQ0YvEy.cjs.map} +1 -1
  104. package/dist/index.cjs +55 -34
  105. package/dist/index.cjs.map +1 -1
  106. package/dist/index.d.cts.map +1 -1
  107. package/dist/index.d.mts.map +1 -1
  108. package/dist/index.mjs +55 -34
  109. package/dist/index.mjs.map +1 -1
  110. package/dist/styles/remote-widget-shadow.css +2 -2
  111. package/dist/{use-internal-link-WJcYzKsi.mjs → use-internal-link-CKMpGvvs.mjs} +2 -2
  112. package/dist/{use-internal-link-WJcYzKsi.mjs.map → use-internal-link-CKMpGvvs.mjs.map} +1 -1
  113. package/dist/{use-internal-link-BTIkbJYg.cjs → use-internal-link-IcDHjPGp.cjs} +2 -2
  114. package/dist/{use-internal-link-BTIkbJYg.cjs.map → use-internal-link-IcDHjPGp.cjs.map} +1 -1
  115. package/dist/{use-link-action-C32zrsI0.mjs → use-link-action-CtVnC_2G.mjs} +2 -2
  116. package/dist/{use-link-action-C32zrsI0.mjs.map → use-link-action-CtVnC_2G.mjs.map} +1 -1
  117. package/dist/{use-link-action-rBy0j6go.cjs → use-link-action-DzA9AQsE.cjs} +2 -2
  118. package/dist/{use-link-action-rBy0j6go.cjs.map → use-link-action-DzA9AQsE.cjs.map} +1 -1
  119. package/dist/{use-portal-card-add-3ds-flow-DhfOxgMV.mjs → use-portal-card-add-3ds-flow-BMHRmeuB.mjs} +3 -3
  120. package/dist/{use-portal-card-add-3ds-flow-DhfOxgMV.mjs.map → use-portal-card-add-3ds-flow-BMHRmeuB.mjs.map} +1 -1
  121. package/dist/{use-portal-card-add-3ds-flow-DUBFzvAB.cjs → use-portal-card-add-3ds-flow-BsSH1Xks.cjs} +3 -3
  122. package/dist/{use-portal-card-add-3ds-flow-DUBFzvAB.cjs.map → use-portal-card-add-3ds-flow-BsSH1Xks.cjs.map} +1 -1
  123. package/dist/utils/build-remote-widget-plugin-manifests.cjs +17 -17
  124. package/dist/utils/build-remote-widget-plugin-manifests.mjs +17 -17
  125. package/dist/utils/build-widget-registry.cjs +17 -17
  126. package/dist/utils/build-widget-registry.mjs +17 -17
  127. package/package.json +19 -19
  128. package/dist/CatchUpWidget-BNEEQNcr.mjs.map +0 -1
  129. package/dist/CatchUpWidget-G4txAfv3.cjs.map +0 -1
  130. package/dist/WidgetInteractionContext-Ba_G5sDP.mjs.map +0 -1
  131. package/dist/WidgetInteractionContext-Bjy4P_YP.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"RecentActivityWidget-DGtKC_9F.mjs","names":[],"sources":["../../widgets/src/hooks/use-activities.preview.ts","../../widgets/src/hooks/use-activities.ts","../../widgets/src/widgets/RecentActivityWidget.tsx"],"sourcesContent":["import type { Activity } from \"@fluid-app/portal-core/widgets-api-types\";\n\nconst now = new Date();\n\nfunction minutesAgo(minutes: number): string {\n return new Date(now.getTime() - minutes * 60_000).toISOString();\n}\n\nexport const PREVIEW_DATA: Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n actor: { type: \"contact\", name: \"Sarah Johnson\" },\n avatarUrl: null,\n activityType: \"Order Placed\",\n targetName: \"Wellness Starter Kit\",\n timestamp: minutesAgo(12),\n slug: \"order_placed\",\n title: \"New order placed\",\n description: \"Wellness Starter Kit\",\n readAt: null,\n urgent: true,\n details: {\n type: \"order\",\n contactName: \"Sarah Johnson\",\n orderTotal: \"129.99\",\n },\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n actor: { type: \"contact\", name: \"Mike Chen\" },\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Signed up from Instagram link\",\n timestamp: minutesAgo(45),\n slug: \"new_lead\",\n title: \"New lead\",\n description: \"Signed up from Instagram link\",\n readAt: null,\n urgent: true,\n details: {\n type: \"contactLead\",\n contactName: \"Mike Chen\",\n leadType: \"instagram\",\n },\n },\n {\n id: 3,\n userName: \"Visitor from Austin, TX\",\n // A real visitor, so the preview exercises the muted, translated treatment\n // rather than showing contact styling under a visitor's label.\n actor: { type: \"visitor\", city: \"Austin\", state: \"TX\" },\n avatarUrl: null,\n activityType: \"Page Views\",\n targetName: \"Viewed product catalog (3 pages)\",\n timestamp: minutesAgo(90),\n slug: \"page_views\",\n title: \"Page viewed\",\n description: \"Viewed product catalog (3 pages)\",\n readAt: minutesAgo(60),\n urgent: false,\n details: {\n type: \"pageView\",\n resourceName: \"Product catalog\",\n },\n },\n {\n id: 4,\n userName: \"Lisa Park\",\n actor: { type: \"contact\", name: \"Lisa Park\" },\n avatarUrl: null,\n activityType: \"Video Complete\",\n targetName: \"Watched: Getting Started Guide\",\n timestamp: minutesAgo(180),\n slug: \"video_complete\",\n title: \"Video finished\",\n description: \"Watched: Getting Started Guide\",\n readAt: minutesAgo(120),\n urgent: false,\n details: {\n type: \"video\",\n contactName: \"Lisa Park\",\n mediumTitle: \"Getting Started Guide\",\n },\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-activities.preview\";\nimport type { ActivitiesPage } from \"@fluid-app/portal-core/widgets-api\";\n\nexport type {\n Activity,\n ActivitySlug,\n} from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type UseActivitiesData = ActivitiesPage;\n\nexport function useActivities(args?: {\n daysAgo?: number;\n}): UseQueryResult<UseActivitiesData, Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"activities\",\n args?.daysAgo ?? null,\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: ({ signal }) => widgetsApi.fetchActivities(args, signal),\n enabled: !isPreview,\n ...(isPreview && {\n // Omit totalCount entirely (rather than setting it to undefined) so\n // tsconfig's exactOptionalPropertyTypes accepts the placeholder shape.\n placeholderData: {\n activities: PREVIEW_DATA,\n nextCursor: null,\n } satisfies UseActivitiesData,\n }),\n });\n}\n","import { useEffect, useMemo, useState, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n borderColorClasses,\n borderWidthClasses,\n getBorderColorField,\n getBorderRadiusField,\n getBorderWidthField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useActivities, type Activity } from \"../hooks/use-activities\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n describeActor,\n EmptyActivityIcon,\n formatActivityDateHeader,\n formatActivityRelativeTime,\n formatActivityTime,\n getActivityDateKey,\n getActivityIcon,\n} from \"@fluid-app/portal-core/activity-presentation\";\nimport { User } from \"lucide-react\";\n\n// ---------- helpers ----------\n\nconst RELATIVE_TIME_REFRESH_MS = 60_000;\nconst DEFAULT_MAX_ITEMS_TO_SHOW = 6;\nconst MAX_ITEMS_TO_SHOW_LIMIT = 20;\n\n// Window matches the Mobile Recent Activity widget, which reads the same\n// days_ago=7 feed, so a rep sees one number across both surfaces.\nconst RECENT_ACTIVITY_DAYS = 7;\n\n// The Activity screen opens on all activity, not this window, so its feed is a\n// superset of what the chip counts. Same split as mobile, where only the Past\n// tab is windowed.\nconst ACTIVITY_SCREEN_SLUG = \"activity\";\n\nconst getColorCssValue = (color: ColorOptions): string =>\n color === \"transparent\" ? \"transparent\" : `var(--color-${color})`;\n\nconst normalizeMaxItemsToShow = (value: number): number => {\n if (!Number.isFinite(value)) return DEFAULT_MAX_ITEMS_TO_SHOW;\n return Math.min(MAX_ITEMS_TO_SHOW_LIMIT, Math.max(1, Math.floor(value)));\n};\n\n// Suppresses the eyebrow when the admin's title already contains it, so a title\n// of \"Recent Activity\" doesn't render as \"RECENT / Recent Activity\". Compared\n// against the translated eyebrow rather than a literal, or the check would only\n// ever work in English.\nconst shouldRenderEyebrow = (\n showEyebrow: boolean,\n titleText: string,\n eyebrowText: string,\n): boolean =>\n showEyebrow &&\n !titleText.trim().toLowerCase().includes(eyebrowText.trim().toLowerCase());\n\n/**\n * Whether the row has nobody to show a face for. Read off the actor rather than\n * sniffed out of the label, which matched the English \"unknown visitor\" and so\n * decided the avatar correctly in one language of the thirty-four.\n */\nconst hasNoKnownPerson = (activity: Activity): boolean =>\n activity.actor.type !== \"contact\";\n\nconst getInitials = (name: string | undefined): string => {\n if (!name) return \"\";\n const parts = name.trim().split(/\\s+/).slice(0, 2);\n return parts.map((p) => p[0]?.toUpperCase() ?? \"\").join(\"\");\n};\n\n// ---------- avatar ----------\n\ntype AvatarProps = {\n activity: Activity;\n textColor: ColorOptions;\n accentColor: ColorOptions;\n surfaceColor: ColorOptions;\n showTypeBadge: boolean;\n};\n\nfunction Avatar({\n activity,\n textColor,\n accentColor,\n surfaceColor,\n showTypeBadge,\n}: AvatarProps) {\n const { t } = useShellTranslation();\n const TypeIcon = getActivityIcon(activity.slug);\n const { label } = describeActor(activity.actor, t);\n const unknown = hasNoKnownPerson(activity);\n const initials = unknown ? \"\" : getInitials(label);\n // 3-tier fallback: image → initials → person icon. If avatarUrl 404s or\n // fails to decode, flip to the next tier instead of showing a broken image.\n const [failedAvatarUrl, setFailedAvatarUrl] = useState<string | null>(null);\n const avatarUrl = activity.avatarUrl;\n const showImage = Boolean(avatarUrl) && failedAvatarUrl !== avatarUrl;\n\n return (\n <div className=\"relative shrink-0\">\n {showImage ? (\n <img\n src={avatarUrl ?? undefined}\n alt={unknown ? \"\" : label}\n width={36}\n height={36}\n loading=\"lazy\"\n onError={() => setFailedAvatarUrl(avatarUrl)}\n className=\"size-9 rounded-full object-cover\"\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n />\n ) : initials ? (\n <div\n className={`flex size-9 items-center justify-center rounded-full text-[11px] font-bold tracking-[0.04em] text-${textColor}/80`}\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 12%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n {initials}\n </div>\n ) : (\n <div\n className={`flex size-9 items-center justify-center rounded-full`}\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 5%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n <User className={`size-3.5 text-${textColor}/55`} />\n </div>\n )}\n\n {/* Type badge — shows what kind of event, regardless of avatar kind. */}\n {showTypeBadge && (\n <span\n className={`bg-${accentColor} text-${accentColor}-foreground absolute -right-0.5 -bottom-0.5 flex size-4 items-center justify-center rounded-full`}\n style={{\n boxShadow: `0 0 0 2px ${getColorCssValue(surfaceColor)}`,\n }}\n aria-hidden=\"true\"\n >\n <TypeIcon style={{ width: 8, height: 8 }} />\n </span>\n )}\n </div>\n );\n}\n\n// ---------- activity row ----------\n\ntype ActivityRowProps = {\n activity: Activity;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n surfaceColor: ColorOptions;\n showRelativeTime: boolean;\n nowMs: number;\n};\n\nfunction ActivityRow({\n activity,\n accentColor,\n textColor,\n surfaceColor,\n showRelativeTime,\n nowMs,\n}: ActivityRowProps) {\n const { t } = useShellTranslation();\n // Same helper the Activity screen uses, so an anonymous visitor reads and looks\n // the same on both surfaces rather than each wording it its own way.\n const { label, muted } = describeActor(activity.actor, t);\n const timeText = showRelativeTime\n ? formatActivityRelativeTime(activity.timestamp, nowMs)\n : formatActivityTime(activity.timestamp);\n\n const absoluteTooltip = new Date(activity.timestamp).toLocaleString(\"en-US\", {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <li\n role=\"article\"\n className=\"relative flex items-start gap-3 rounded-md p-2\"\n >\n <Avatar\n activity={activity}\n textColor={textColor}\n accentColor={accentColor}\n surfaceColor={surfaceColor}\n showTypeBadge\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex items-baseline gap-2\">\n <p\n className={`min-w-0 flex-1 truncate text-[13px] leading-tight font-semibold text-${textColor}`}\n >\n {activity.activityType}\n </p>\n <span\n title={absoluteTooltip}\n className={`shrink-0 font-mono text-[10px] font-medium tabular-nums text-${textColor}/45`}\n >\n {timeText}\n </span>\n </div>\n <p\n className={`mt-0.5 truncate text-[12px] leading-snug text-${textColor}/65`}\n >\n <span\n className={`font-semibold text-${textColor}/85${muted ? \" italic\" : \"\"}`}\n >\n {label}\n </span>\n {activity.targetName && (\n <>\n <span className={`mx-1 text-${textColor}/35`}>·</span>\n <span>{activity.targetName}</span>\n </>\n )}\n </p>\n </div>\n </li>\n );\n}\n\n// ---------- widget ----------\n\ntype RecentActivityWidgetProps = ComponentProps<\"div\"> & {\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n maxItemsToShow?: number;\n\n // Polish (additive)\n showTimeline?: boolean;\n showRelativeTime?: boolean;\n showCountChip?: boolean;\n showEyebrow?: boolean;\n};\n\nfunction useRelativeTimeNow(): number {\n const [nowMs, setNowMs] = useState(() => Date.now());\n\n useEffect(() => {\n const timer = window.setInterval(() => {\n setNowMs(Date.now());\n }, RELATIVE_TIME_REFRESH_MS);\n\n return () => window.clearInterval(timer);\n }, []);\n\n return nowMs;\n}\n\nexport function RecentActivityWidget({\n titleEnabled = true,\n titleText = \"Activity\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n background = { type: \"solid\", color: \"background\" },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"thin\",\n borderColor = \"muted\",\n\n maxItemsToShow = 6,\n\n // showTimeline is intentionally not destructured. The spine it once\n // controlled is no longer rendered. The prop stays on the type so saved\n // widget configs don't fail schema validation.\n showRelativeTime = true,\n showCountChip = true,\n showEyebrow = true,\n\n className,\n onClick: onClickProp,\n ...props\n}: RecentActivityWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n // Rep-facing copy reads the same shell keys the Activity screen does, so the two\n // surfaces cannot drift. The untranslated strings further down are builder field\n // labels and descriptions, which the editor shows an admin rather than a rep.\n const { t } = useShellTranslation();\n\n // Absent in the builder preview, which is how the preview stays inert.\n const { onNavigate } = useWidgetInteraction();\n // The Activity screen is tenant-flagged (PORTAL_ACTIVITY_SCREEN). Without it\n // the widget is a plain summary again: no click-through to offer.\n const { data: store } = useOptionalStore();\n const canNavigate =\n Boolean(onNavigate) && store?.activity_screen_enabled === true;\n\n const goToActivityScreen = () => {\n if (!canNavigate) return;\n onNavigate?.(ACTIVITY_SCREEN_SLUG);\n };\n\n // Clicking anywhere on the card navigates, but the card is not itself a\n // control — the \"View all\" button below is, so keyboard and screen-reader\n // users get a real target without nesting interactive elements.\n const handleRootClick = (event: React.MouseEvent<HTMLDivElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n goToActivityScreen();\n };\n\n const { data, isLoading, isError } = useActivities({\n daysAgo: RECENT_ACTIVITY_DAYS,\n });\n // Stabilize the empty-fallback reference so downstream `useMemo` deps don't\n // see a fresh `[]` on every render.\n const activities = useMemo(() => data?.activities ?? [], [data]);\n const windowedTotal = data?.totalCount;\n const nowMs = useRelativeTimeNow();\n const maxVisibleItems = normalizeMaxItemsToShow(maxItemsToShow);\n const dayLabels = useMemo(\n () => ({\n today: t(\"activity_date_today\"),\n yesterday: t(\"activity_date_yesterday\"),\n }),\n [t],\n );\n\n const activitiesToShow = useMemo(() => {\n if (activities.length === 0)\n return [] as { date: string; items: Activity[] }[];\n const groups = new Map<string, Activity[]>();\n for (const activity of activities.slice(0, maxVisibleItems)) {\n const key = getActivityDateKey(activity.timestamp);\n const existing = groups.get(key);\n if (existing) existing.push(activity);\n else groups.set(key, [activity]);\n }\n return Array.from(groups.entries()).map(([key, items]) => ({\n // `key` is only a defensive fallback; every group is created with at\n // least one activity, so the item timestamp is what normally labels it.\n date: formatActivityDateHeader(\n items[0]?.timestamp ?? key,\n nowMs,\n dayLabels,\n ),\n items,\n }));\n }, [activities, maxVisibleItems, nowMs, dayLabels]);\n\n // Prefer the server total. Fall back to the visible list length when the\n // adapter does not return one, so the widget keeps working before every\n // data path returns a count.\n const totalCount =\n windowedTotal ?? Math.min(activities.length, maxVisibleItems);\n\n return (\n <div\n onClick={canNavigate || onClickProp ? handleRootClick : undefined}\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${canNavigate ? \"cursor-pointer\" : \"\"} ${className ?? \"\"}`}\n style={{\n backgroundImage,\n // Soft ambient lift derived from theme tokens. The configured border\n // props own the crisp outline so saved border settings stay intact.\n boxShadow: `0 1px 2px color-mix(in oklch, var(--color-foreground) 4%, transparent), 0 14px 32px -20px color-mix(in oklch, var(--color-foreground) 14%, transparent)`,\n }}\n {...props}\n >\n <div className={`p-${padding} flex flex-col`}>\n {/* Header */}\n {titleEnabled && titleText && (\n <div className=\"mb-4 flex items-end justify-between gap-3\">\n <div className=\"flex min-w-0 flex-col\">\n {shouldRenderEyebrow(\n showEyebrow,\n titleText,\n t(\"activity_widget_eyebrow\"),\n ) && (\n <span\n className={`text-[10px] font-bold tracking-[0.2em] uppercase text-${textColor}/55`}\n >\n {t(\"activity_widget_eyebrow\")}\n </span>\n )}\n <h2\n className={`mt-0.5 text-${titleFontSize} leading-tight font-bold tracking-[-0.015em] text-${titleColor}`}\n >\n {titleText}\n </h2>\n <span\n className={`mt-0.5 text-xs font-medium text-${textColor}/60`}\n >\n {t(\"activity_widget_window\", { days: RECENT_ACTIVITY_DAYS })}\n </span>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {!isLoading && !isError && showCountChip && totalCount > 0 && (\n <span\n className={`inline-flex shrink-0 items-center gap-1.5 rounded-full bg-${accentColor}/10 px-2 py-1 text-[10px] font-bold tracking-[0.06em] text-${accentColor}`}\n >\n <span\n aria-hidden=\"true\"\n className={`size-1.5 rounded-full bg-${accentColor}`}\n />\n {t(\"activity_widget_updates\", { count: totalCount })}\n </span>\n )}\n {canNavigate && (\n <button\n type=\"button\"\n onClick={(event) => {\n // The card handles clicks too; stop here so one click is\n // one navigation.\n event.stopPropagation();\n goToActivityScreen();\n }}\n className={`shrink-0 rounded-md px-1.5 py-1 text-[11px] font-bold text-${accentColor} hover:bg-${accentColor}/10 focus-visible:ring-${accentColor} focus-visible:ring-2 focus-visible:outline-none`}\n >\n {t(\"activity_view_all\")}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* States */}\n {isLoading ? (\n <ActivitySkeleton textColor={textColor} rowCount={maxVisibleItems} />\n ) : isError ? (\n <ErrorState />\n ) : activities.length === 0 ? (\n <EmptyState textColor={textColor} accentColor={accentColor} />\n ) : (\n /* Feed */\n <div role=\"feed\" className=\"flex flex-col gap-3\">\n {activitiesToShow.map((group, groupIdx) => (\n <section\n key={`${group.date}-${groupIdx}`}\n className=\"flex flex-col gap-1\"\n >\n <header className=\"flex items-center gap-2 px-2\">\n <span\n className={`text-[10px] font-bold tracking-[0.18em] uppercase text-${textColor}/55`}\n >\n {group.date}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1\"\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n />\n </header>\n\n <ul className=\"relative flex flex-col\">\n {/* No timeline spine. An earlier version drew a single\n line at the avatar column, which the avatars occluded,\n leaving only fragmented stubs between rows. */}\n {group.items.map((activity) => (\n <ActivityRow\n key={activity.id}\n activity={activity}\n accentColor={accentColor}\n textColor={textColor}\n surfaceColor={backgroundColor}\n showRelativeTime={showRelativeTime}\n nowMs={nowMs}\n />\n ))}\n </ul>\n </section>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n// ---------- empty state ----------\n\ntype EmptyStateProps = {\n textColor: ColorOptions;\n accentColor: ColorOptions;\n};\n\nfunction EmptyState({ textColor, accentColor }: EmptyStateProps) {\n const { t } = useShellTranslation();\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 py-10\">\n <div\n className=\"relative flex size-12 items-center justify-center rounded-full\"\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 10%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n >\n <EmptyActivityIcon className={`size-5 text-${accentColor}/80`} />\n </div>\n <div className=\"flex flex-col items-center gap-1\">\n <p className={`text-[13px] font-semibold text-${textColor}/80`}>\n {t(\"activity_empty_title\")}\n </p>\n <p\n className={`max-w-[24ch] text-center text-[11px] leading-snug text-${textColor}/55`}\n >\n {t(\"activity_empty_description\")}\n </p>\n </div>\n </div>\n );\n}\n\n// ---------- skeleton ----------\n\ntype ActivitySkeletonProps = {\n textColor: ColorOptions;\n rowCount: number;\n};\n\nfunction ActivitySkeleton({ textColor, rowCount }: ActivitySkeletonProps) {\n return (\n <div className=\"relative flex flex-col\" aria-busy=\"true\">\n {/* No skeleton spine; the loaded state doesn't draw one either. */}\n {Array.from({ length: rowCount }, (_, i) => i).map((i) => (\n <div key={i} className=\"relative flex items-start gap-3 rounded-md p-2\">\n <div\n className={`size-9 shrink-0 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div\n className={`h-2 w-2/3 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div\n className={`h-2 w-1/2 animate-pulse rounded-full bg-${textColor}/10`}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\n// ---------- schema ----------\n\nexport const recentActivityWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"RecentActivityWidget\",\n displayName: \"Recent Activity Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Title\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Display the title and eyebrow above the feed\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the activity feed\",\n defaultValue: \"Activity\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n {\n key: \"showEyebrow\",\n label: \"Show 'RECENT' Eyebrow\",\n type: \"boolean\",\n description: \"Small uppercase label above the title\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n {\n key: \"showCountChip\",\n label: \"Show Updates Count Chip\",\n type: \"boolean\",\n description: \"Accent pill next to the title showing how many updates\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n\n // Feed\n {\n key: \"maxItemsToShow\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of activity items to display\",\n defaultValue: DEFAULT_MAX_ITEMS_TO_SHOW,\n min: 1,\n max: MAX_ITEMS_TO_SHOW_LIMIT,\n step: 1,\n tab: \"styling\",\n group: \"Feed\",\n },\n {\n key: \"showRelativeTime\",\n label: \"Relative Timestamps\",\n type: \"boolean\",\n description: \"Show 'now / 2m / 1h / 3d' instead of absolute times\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Feed\",\n },\n\n // Design\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: { type: \"solid\", color: \"background\" },\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for activity content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description:\n \"Drives the count chip, type badge, initials avatar, and empty-state icon\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget container\",\n defaultValue: \"thin\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget container\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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L,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,KAAK;GACL,MAAM;GACN,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EAGD;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;IAAE,MAAM;IAAS,OAAO;IAAc;GACpD,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH;CACF"}
1
+ {"version":3,"file":"RecentActivityWidget-BzmV4G8e.mjs","names":[],"sources":["../../widgets/src/hooks/use-activities.preview.ts","../../widgets/src/hooks/use-activities.ts","../../widgets/src/widgets/RecentActivityWidget.tsx"],"sourcesContent":["import type { Activity } from \"@fluid-app/portal-core/widgets-api-types\";\n\nconst now = new Date();\n\nfunction minutesAgo(minutes: number): string {\n return new Date(now.getTime() - minutes * 60_000).toISOString();\n}\n\nexport const PREVIEW_DATA: Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n actor: { type: \"contact\", name: \"Sarah Johnson\" },\n avatarUrl: null,\n activityType: \"Order Placed\",\n targetName: \"Wellness Starter Kit\",\n timestamp: minutesAgo(12),\n slug: \"order_placed\",\n title: \"New order placed\",\n description: \"Wellness Starter Kit\",\n readAt: null,\n urgent: true,\n details: {\n type: \"order\",\n contactName: \"Sarah Johnson\",\n orderTotal: \"129.99\",\n },\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n actor: { type: \"contact\", name: \"Mike Chen\" },\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Signed up from Instagram link\",\n timestamp: minutesAgo(45),\n slug: \"new_lead\",\n title: \"New lead\",\n description: \"Signed up from Instagram link\",\n readAt: null,\n urgent: true,\n details: {\n type: \"contactLead\",\n contactName: \"Mike Chen\",\n leadType: \"instagram\",\n },\n },\n {\n id: 3,\n userName: \"Visitor from Austin, TX\",\n // A real visitor, so the preview exercises the muted, translated treatment\n // rather than showing contact styling under a visitor's label.\n actor: { type: \"visitor\", city: \"Austin\", state: \"TX\" },\n avatarUrl: null,\n activityType: \"Page Views\",\n targetName: \"Viewed product catalog (3 pages)\",\n timestamp: minutesAgo(90),\n slug: \"page_views\",\n title: \"Page viewed\",\n description: \"Viewed product catalog (3 pages)\",\n readAt: minutesAgo(60),\n urgent: false,\n details: {\n type: \"pageView\",\n resourceName: \"Product catalog\",\n },\n },\n {\n id: 4,\n userName: \"Lisa Park\",\n actor: { type: \"contact\", name: \"Lisa Park\" },\n avatarUrl: null,\n activityType: \"Video Complete\",\n targetName: \"Watched: Getting Started Guide\",\n timestamp: minutesAgo(180),\n slug: \"video_complete\",\n title: \"Video finished\",\n description: \"Watched: Getting Started Guide\",\n readAt: minutesAgo(120),\n urgent: false,\n details: {\n type: \"video\",\n contactName: \"Lisa Park\",\n mediumTitle: \"Getting Started Guide\",\n },\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-activities.preview\";\nimport type { ActivitiesPage } from \"@fluid-app/portal-core/widgets-api\";\n\nexport type {\n Activity,\n ActivitySlug,\n} from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type UseActivitiesData = ActivitiesPage;\n\nexport function useActivities(args?: {\n daysAgo?: number;\n}): UseQueryResult<UseActivitiesData, Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"activities\",\n args?.daysAgo ?? null,\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: ({ signal }) => widgetsApi.fetchActivities(args, signal),\n enabled: !isPreview,\n ...(isPreview && {\n // Omit totalCount entirely (rather than setting it to undefined) so\n // tsconfig's exactOptionalPropertyTypes accepts the placeholder shape.\n placeholderData: {\n activities: PREVIEW_DATA,\n nextCursor: null,\n } satisfies UseActivitiesData,\n }),\n });\n}\n","import { useEffect, useMemo, useState, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n borderColorClasses,\n borderWidthClasses,\n getBorderColorField,\n getBorderRadiusField,\n getBorderWidthField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useActivities, type Activity } from \"../hooks/use-activities\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n describeActor,\n EmptyActivityIcon,\n formatActivityDateHeader,\n formatActivityRelativeTime,\n formatActivityTime,\n getActivityDateKey,\n getActivityIcon,\n} from \"@fluid-app/portal-core/activity-presentation\";\nimport { User } from \"lucide-react\";\n\n// ---------- helpers ----------\n\nconst RELATIVE_TIME_REFRESH_MS = 60_000;\nconst DEFAULT_MAX_ITEMS_TO_SHOW = 6;\nconst MAX_ITEMS_TO_SHOW_LIMIT = 20;\n\n// Window matches the Mobile Recent Activity widget, which reads the same\n// days_ago=7 feed, so a rep sees one number across both surfaces.\nconst RECENT_ACTIVITY_DAYS = 7;\n\n// The Activity screen opens on all activity, not this window, so its feed is a\n// superset of what the chip counts. Same split as mobile, where only the Past\n// tab is windowed.\nconst ACTIVITY_SCREEN_SLUG = \"activity\";\n\nconst getColorCssValue = (color: ColorOptions): string =>\n color === \"transparent\" ? \"transparent\" : `var(--color-${color})`;\n\nconst normalizeMaxItemsToShow = (value: number): number => {\n if (!Number.isFinite(value)) return DEFAULT_MAX_ITEMS_TO_SHOW;\n return Math.min(MAX_ITEMS_TO_SHOW_LIMIT, Math.max(1, Math.floor(value)));\n};\n\n// Suppresses the eyebrow when the admin's title already contains it, so a title\n// of \"Recent Activity\" doesn't render as \"RECENT / Recent Activity\". Compared\n// against the translated eyebrow rather than a literal, or the check would only\n// ever work in English.\nconst shouldRenderEyebrow = (\n showEyebrow: boolean,\n titleText: string,\n eyebrowText: string,\n): boolean =>\n showEyebrow &&\n !titleText.trim().toLowerCase().includes(eyebrowText.trim().toLowerCase());\n\n/**\n * Whether the row has nobody to show a face for. Read off the actor rather than\n * sniffed out of the label, which matched the English \"unknown visitor\" and so\n * decided the avatar correctly in one language of the thirty-four.\n */\nconst hasNoKnownPerson = (activity: Activity): boolean =>\n activity.actor.type !== \"contact\";\n\nconst getInitials = (name: string | undefined): string => {\n if (!name) return \"\";\n const parts = name.trim().split(/\\s+/).slice(0, 2);\n return parts.map((p) => p[0]?.toUpperCase() ?? \"\").join(\"\");\n};\n\n// ---------- avatar ----------\n\ntype AvatarProps = {\n activity: Activity;\n textColor: ColorOptions;\n accentColor: ColorOptions;\n surfaceColor: ColorOptions;\n showTypeBadge: boolean;\n};\n\nfunction Avatar({\n activity,\n textColor,\n accentColor,\n surfaceColor,\n showTypeBadge,\n}: AvatarProps) {\n const { t } = useShellTranslation();\n const TypeIcon = getActivityIcon(activity.slug);\n const { label } = describeActor(activity.actor, t);\n const unknown = hasNoKnownPerson(activity);\n const initials = unknown ? \"\" : getInitials(label);\n // 3-tier fallback: image → initials → person icon. If avatarUrl 404s or\n // fails to decode, flip to the next tier instead of showing a broken image.\n const [failedAvatarUrl, setFailedAvatarUrl] = useState<string | null>(null);\n const avatarUrl = activity.avatarUrl;\n const showImage = Boolean(avatarUrl) && failedAvatarUrl !== avatarUrl;\n\n return (\n <div className=\"relative shrink-0\">\n {showImage ? (\n <img\n src={avatarUrl ?? undefined}\n alt={unknown ? \"\" : label}\n width={36}\n height={36}\n loading=\"lazy\"\n onError={() => setFailedAvatarUrl(avatarUrl)}\n className=\"size-9 rounded-full object-cover\"\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n />\n ) : initials ? (\n <div\n className={`flex size-9 items-center justify-center rounded-full text-[11px] font-bold tracking-[0.04em] text-${textColor}/80`}\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 12%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n {initials}\n </div>\n ) : (\n <div\n className={`flex size-9 items-center justify-center rounded-full`}\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 5%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n <User className={`size-3.5 text-${textColor}/55`} />\n </div>\n )}\n\n {/* Type badge — shows what kind of event, regardless of avatar kind. */}\n {showTypeBadge && (\n <span\n className={`bg-${accentColor} text-${accentColor}-foreground absolute -right-0.5 -bottom-0.5 flex size-4 items-center justify-center rounded-full`}\n style={{\n boxShadow: `0 0 0 2px ${getColorCssValue(surfaceColor)}`,\n }}\n aria-hidden=\"true\"\n >\n <TypeIcon style={{ width: 8, height: 8 }} />\n </span>\n )}\n </div>\n );\n}\n\n// ---------- activity row ----------\n\ntype ActivityRowProps = {\n activity: Activity;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n surfaceColor: ColorOptions;\n showRelativeTime: boolean;\n nowMs: number;\n};\n\nfunction ActivityRow({\n activity,\n accentColor,\n textColor,\n surfaceColor,\n showRelativeTime,\n nowMs,\n}: ActivityRowProps) {\n const { t } = useShellTranslation();\n // Same helper the Activity screen uses, so an anonymous visitor reads and looks\n // the same on both surfaces rather than each wording it its own way.\n const { label, muted } = describeActor(activity.actor, t);\n const timeText = showRelativeTime\n ? formatActivityRelativeTime(activity.timestamp, nowMs)\n : formatActivityTime(activity.timestamp);\n\n const absoluteTooltip = new Date(activity.timestamp).toLocaleString(\"en-US\", {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <li\n role=\"article\"\n className=\"relative flex items-start gap-3 rounded-md p-2\"\n >\n <Avatar\n activity={activity}\n textColor={textColor}\n accentColor={accentColor}\n surfaceColor={surfaceColor}\n showTypeBadge\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex items-baseline gap-2\">\n <p\n className={`min-w-0 flex-1 truncate text-[13px] leading-tight font-semibold text-${textColor}`}\n >\n {activity.activityType}\n </p>\n <span\n title={absoluteTooltip}\n className={`shrink-0 font-mono text-[10px] font-medium tabular-nums text-${textColor}/45`}\n >\n {timeText}\n </span>\n </div>\n <p\n className={`mt-0.5 truncate text-[12px] leading-snug text-${textColor}/65`}\n >\n <span\n className={`font-semibold text-${textColor}/85${muted ? \" italic\" : \"\"}`}\n >\n {label}\n </span>\n {activity.targetName && (\n <>\n <span className={`mx-1 text-${textColor}/35`}>·</span>\n <span>{activity.targetName}</span>\n </>\n )}\n </p>\n </div>\n </li>\n );\n}\n\n// ---------- widget ----------\n\ntype RecentActivityWidgetProps = ComponentProps<\"div\"> & {\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n maxItemsToShow?: number;\n\n // Polish (additive)\n showTimeline?: boolean;\n showRelativeTime?: boolean;\n showCountChip?: boolean;\n showEyebrow?: boolean;\n};\n\nfunction useRelativeTimeNow(): number {\n const [nowMs, setNowMs] = useState(() => Date.now());\n\n useEffect(() => {\n const timer = window.setInterval(() => {\n setNowMs(Date.now());\n }, RELATIVE_TIME_REFRESH_MS);\n\n return () => window.clearInterval(timer);\n }, []);\n\n return nowMs;\n}\n\nexport function RecentActivityWidget({\n titleEnabled = true,\n titleText = \"Activity\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n background = { type: \"solid\", color: \"background\" },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"thin\",\n borderColor = \"muted\",\n\n maxItemsToShow = 6,\n\n // showTimeline is intentionally not destructured. The spine it once\n // controlled is no longer rendered. The prop stays on the type so saved\n // widget configs don't fail schema validation.\n showRelativeTime = true,\n showCountChip = true,\n showEyebrow = true,\n\n className,\n onClick: onClickProp,\n ...props\n}: RecentActivityWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n // Rep-facing copy reads the same shell keys the Activity screen does, so the two\n // surfaces cannot drift. The untranslated strings further down are builder field\n // labels and descriptions, which the editor shows an admin rather than a rep.\n const { t } = useShellTranslation();\n\n // Absent in the builder preview, which is how the preview stays inert.\n const { onNavigate } = useWidgetInteraction();\n // The Activity screen is tenant-flagged (PORTAL_ACTIVITY_SCREEN). Without it\n // the widget is a plain summary again: no click-through to offer.\n const { data: store } = useOptionalStore();\n const canNavigate =\n Boolean(onNavigate) && store?.activity_screen_enabled === true;\n\n const goToActivityScreen = () => {\n if (!canNavigate) return;\n onNavigate?.(ACTIVITY_SCREEN_SLUG);\n };\n\n // Clicking anywhere on the card navigates, but the card is not itself a\n // control — the \"View all\" button below is, so keyboard and screen-reader\n // users get a real target without nesting interactive elements.\n const handleRootClick = (event: React.MouseEvent<HTMLDivElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n goToActivityScreen();\n };\n\n const { data, isLoading, isError } = useActivities({\n daysAgo: RECENT_ACTIVITY_DAYS,\n });\n // Stabilize the empty-fallback reference so downstream `useMemo` deps don't\n // see a fresh `[]` on every render.\n const activities = useMemo(() => data?.activities ?? [], [data]);\n const windowedTotal = data?.totalCount;\n const nowMs = useRelativeTimeNow();\n const maxVisibleItems = normalizeMaxItemsToShow(maxItemsToShow);\n const dayLabels = useMemo(\n () => ({\n today: t(\"activity_date_today\"),\n yesterday: t(\"activity_date_yesterday\"),\n }),\n [t],\n );\n\n const activitiesToShow = useMemo(() => {\n if (activities.length === 0)\n return [] as { date: string; items: Activity[] }[];\n const groups = new Map<string, Activity[]>();\n for (const activity of activities.slice(0, maxVisibleItems)) {\n const key = getActivityDateKey(activity.timestamp);\n const existing = groups.get(key);\n if (existing) existing.push(activity);\n else groups.set(key, [activity]);\n }\n return Array.from(groups.entries()).map(([key, items]) => ({\n // `key` is only a defensive fallback; every group is created with at\n // least one activity, so the item timestamp is what normally labels it.\n date: formatActivityDateHeader(\n items[0]?.timestamp ?? key,\n nowMs,\n dayLabels,\n ),\n items,\n }));\n }, [activities, maxVisibleItems, nowMs, dayLabels]);\n\n // Prefer the server total. Fall back to the visible list length when the\n // adapter does not return one, so the widget keeps working before every\n // data path returns a count.\n const totalCount =\n windowedTotal ?? Math.min(activities.length, maxVisibleItems);\n\n return (\n <div\n onClick={canNavigate || onClickProp ? handleRootClick : undefined}\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${canNavigate ? \"cursor-pointer\" : \"\"} ${className ?? \"\"}`}\n style={{\n backgroundImage,\n // Soft ambient lift derived from theme tokens. The configured border\n // props own the crisp outline so saved border settings stay intact.\n boxShadow: `0 1px 2px color-mix(in oklch, var(--color-foreground) 4%, transparent), 0 14px 32px -20px color-mix(in oklch, var(--color-foreground) 14%, transparent)`,\n }}\n {...props}\n >\n <div className={`p-${padding} flex flex-col`}>\n {/* Header */}\n {titleEnabled && titleText && (\n <div className=\"mb-4 flex items-end justify-between gap-3\">\n <div className=\"flex min-w-0 flex-col\">\n {shouldRenderEyebrow(\n showEyebrow,\n titleText,\n t(\"activity_widget_eyebrow\"),\n ) && (\n <span\n className={`text-[10px] font-bold tracking-[0.2em] uppercase text-${textColor}/55`}\n >\n {t(\"activity_widget_eyebrow\")}\n </span>\n )}\n <h2\n className={`mt-0.5 text-${titleFontSize} leading-tight font-bold tracking-[-0.015em] text-${titleColor}`}\n >\n {titleText}\n </h2>\n <span\n className={`mt-0.5 text-xs font-medium text-${textColor}/60`}\n >\n {t(\"activity_widget_window\", { days: RECENT_ACTIVITY_DAYS })}\n </span>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {!isLoading && !isError && showCountChip && totalCount > 0 && (\n <span\n className={`inline-flex shrink-0 items-center gap-1.5 rounded-full bg-${accentColor}/10 px-2 py-1 text-[10px] font-bold tracking-[0.06em] text-${accentColor}`}\n >\n <span\n aria-hidden=\"true\"\n className={`size-1.5 rounded-full bg-${accentColor}`}\n />\n {t(\"activity_widget_updates\", { count: totalCount })}\n </span>\n )}\n {canNavigate && (\n <button\n type=\"button\"\n onClick={(event) => {\n // The card handles clicks too; stop here so one click is\n // one navigation.\n event.stopPropagation();\n goToActivityScreen();\n }}\n className={`shrink-0 rounded-md px-1.5 py-1 text-[11px] font-bold text-${accentColor} hover:bg-${accentColor}/10 focus-visible:ring-${accentColor} focus-visible:ring-2 focus-visible:outline-none`}\n >\n {t(\"activity_view_all\")}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* States */}\n {isLoading ? (\n <ActivitySkeleton textColor={textColor} rowCount={maxVisibleItems} />\n ) : isError ? (\n <ErrorState />\n ) : activities.length === 0 ? (\n <EmptyState textColor={textColor} accentColor={accentColor} />\n ) : (\n /* Feed */\n <div role=\"feed\" className=\"flex flex-col gap-3\">\n {activitiesToShow.map((group, groupIdx) => (\n <section\n key={`${group.date}-${groupIdx}`}\n className=\"flex flex-col gap-1\"\n >\n <header className=\"flex items-center gap-2 px-2\">\n <span\n className={`text-[10px] font-bold tracking-[0.18em] uppercase text-${textColor}/55`}\n >\n {group.date}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1\"\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n />\n </header>\n\n <ul className=\"relative flex flex-col\">\n {/* No timeline spine. An earlier version drew a single\n line at the avatar column, which the avatars occluded,\n leaving only fragmented stubs between rows. */}\n {group.items.map((activity) => (\n <ActivityRow\n key={activity.id}\n activity={activity}\n accentColor={accentColor}\n textColor={textColor}\n surfaceColor={backgroundColor}\n showRelativeTime={showRelativeTime}\n nowMs={nowMs}\n />\n ))}\n </ul>\n </section>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n// ---------- empty state ----------\n\ntype EmptyStateProps = {\n textColor: ColorOptions;\n accentColor: ColorOptions;\n};\n\nfunction EmptyState({ textColor, accentColor }: EmptyStateProps) {\n const { t } = useShellTranslation();\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 py-10\">\n <div\n className=\"relative flex size-12 items-center justify-center rounded-full\"\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 10%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n >\n <EmptyActivityIcon className={`size-5 text-${accentColor}/80`} />\n </div>\n <div className=\"flex flex-col items-center gap-1\">\n <p className={`text-[13px] font-semibold text-${textColor}/80`}>\n {t(\"activity_empty_title\")}\n </p>\n <p\n className={`max-w-[24ch] text-center text-[11px] leading-snug text-${textColor}/55`}\n >\n {t(\"activity_empty_description\")}\n </p>\n </div>\n </div>\n );\n}\n\n// ---------- skeleton ----------\n\ntype ActivitySkeletonProps = {\n textColor: ColorOptions;\n rowCount: number;\n};\n\nfunction ActivitySkeleton({ textColor, rowCount }: ActivitySkeletonProps) {\n return (\n <div className=\"relative flex flex-col\" aria-busy=\"true\">\n {/* No skeleton spine; the loaded state doesn't draw one either. */}\n {Array.from({ length: rowCount }, (_, i) => i).map((i) => (\n <div key={i} className=\"relative flex items-start gap-3 rounded-md p-2\">\n <div\n className={`size-9 shrink-0 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div\n className={`h-2 w-2/3 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div\n className={`h-2 w-1/2 animate-pulse rounded-full bg-${textColor}/10`}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\n// ---------- schema ----------\n\nexport const recentActivityWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"RecentActivityWidget\",\n displayName: \"Recent Activity Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Title\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Display the title and eyebrow above the feed\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the activity feed\",\n defaultValue: \"Activity\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n {\n key: \"showEyebrow\",\n label: \"Show 'RECENT' Eyebrow\",\n type: \"boolean\",\n description: \"Small uppercase label above the title\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n {\n key: \"showCountChip\",\n label: \"Show Updates Count Chip\",\n type: \"boolean\",\n description: \"Accent pill next to the title showing how many updates\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n\n // Feed\n {\n key: \"maxItemsToShow\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of activity items to display\",\n defaultValue: DEFAULT_MAX_ITEMS_TO_SHOW,\n min: 1,\n max: MAX_ITEMS_TO_SHOW_LIMIT,\n step: 1,\n tab: \"styling\",\n group: \"Feed\",\n },\n {\n key: \"showRelativeTime\",\n label: \"Relative Timestamps\",\n type: \"boolean\",\n description: \"Show 'now / 2m / 1h / 3d' instead of absolute times\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Feed\",\n },\n\n // Design\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: { type: \"solid\", color: \"background\" },\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for activity content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description:\n \"Drives the count chip, type badge, initials avatar, and empty-state icon\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget container\",\n defaultValue: \"thin\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget container\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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L,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,KAAK;GACL,MAAM;GACN,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EAGD;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;IAAE,MAAM;IAAS,OAAO;IAAc;GACpD,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH;CACF"}
@@ -1,7 +1,7 @@
1
1
  require("./chunk-9hOWP6kD.cjs");
2
2
  require("./use-optional-store-CIM4spDu.cjs");
3
3
  require("./registry-context-DLWP4Bzy.cjs");
4
- require("./WidgetInteractionContext-Bjy4P_YP.cjs");
4
+ require("./WidgetInteractionContext-D9dBJ-39.cjs");
5
5
  require("./translation-api-context-factory-mbsJk2UU.cjs");
6
6
  require("./shell-translation-api-context-BxZ1W6Eb.cjs");
7
7
  require("./widgets-api-context-CdgvPvNT.cjs");
@@ -9,6 +9,6 @@ require("./registries-MpWTUak_.cjs");
9
9
  require("./fields-DbTpcT4E.cjs");
10
10
  require("./preview-context-DDYz757l.cjs");
11
11
  require("./error-state-9EyOWmGK.cjs");
12
- const require_RecentActivityWidget = require("./RecentActivityWidget-Cr1G82Cd.cjs");
12
+ const require_RecentActivityWidget = require("./RecentActivityWidget-zBOY0c_B.cjs");
13
13
  require("./activity-presentation-Bant06dK.cjs");
14
14
  exports.recentActivityWidgetPropertySchema = require_RecentActivityWidget.recentActivityWidgetPropertySchema;
@@ -1,7 +1,7 @@
1
1
  require("./chunk-9hOWP6kD.cjs");
2
2
  const require_use_optional_store = require("./use-optional-store-CIM4spDu.cjs");
3
3
  const require_registry_context = require("./registry-context-DLWP4Bzy.cjs");
4
- const require_WidgetInteractionContext = require("./WidgetInteractionContext-Bjy4P_YP.cjs");
4
+ const require_WidgetInteractionContext = require("./WidgetInteractionContext-D9dBJ-39.cjs");
5
5
  const require_shell_translation_api_context = require("./shell-translation-api-context-BxZ1W6Eb.cjs");
6
6
  const require_widgets_api_context = require("./widgets-api-context-CdgvPvNT.cjs");
7
7
  const require_registries = require("./registries-MpWTUak_.cjs");
@@ -588,4 +588,4 @@ Object.defineProperty(exports, "recentActivityWidgetPropertySchema", {
588
588
  }
589
589
  });
590
590
 
591
- //# sourceMappingURL=RecentActivityWidget-Cr1G82Cd.cjs.map
591
+ //# sourceMappingURL=RecentActivityWidget-zBOY0c_B.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"RecentActivityWidget-Cr1G82Cd.cjs","names":["useWidgetsApi","useWidgetPreviewContext","useDataSourceRegistryConfig","useShellTranslation","getActivityIcon","describeActor","User","formatActivityRelativeTime","formatActivityTime","useWidgetInteraction","useOptionalStore","getActivityDateKey","formatActivityDateHeader","borderWidthClasses","borderColorClasses","ErrorState","EmptyActivityIcon","getFontSizeField","getColorField","getPaddingField","getBorderRadiusField","getBorderWidthField","getBorderColorField"],"sources":["../../widgets/src/hooks/use-activities.preview.ts","../../widgets/src/hooks/use-activities.ts","../../widgets/src/widgets/RecentActivityWidget.tsx"],"sourcesContent":["import type { Activity } from \"@fluid-app/portal-core/widgets-api-types\";\n\nconst now = new Date();\n\nfunction minutesAgo(minutes: number): string {\n return new Date(now.getTime() - minutes * 60_000).toISOString();\n}\n\nexport const PREVIEW_DATA: Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n actor: { type: \"contact\", name: \"Sarah Johnson\" },\n avatarUrl: null,\n activityType: \"Order Placed\",\n targetName: \"Wellness Starter Kit\",\n timestamp: minutesAgo(12),\n slug: \"order_placed\",\n title: \"New order placed\",\n description: \"Wellness Starter Kit\",\n readAt: null,\n urgent: true,\n details: {\n type: \"order\",\n contactName: \"Sarah Johnson\",\n orderTotal: \"129.99\",\n },\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n actor: { type: \"contact\", name: \"Mike Chen\" },\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Signed up from Instagram link\",\n timestamp: minutesAgo(45),\n slug: \"new_lead\",\n title: \"New lead\",\n description: \"Signed up from Instagram link\",\n readAt: null,\n urgent: true,\n details: {\n type: \"contactLead\",\n contactName: \"Mike Chen\",\n leadType: \"instagram\",\n },\n },\n {\n id: 3,\n userName: \"Visitor from Austin, TX\",\n // A real visitor, so the preview exercises the muted, translated treatment\n // rather than showing contact styling under a visitor's label.\n actor: { type: \"visitor\", city: \"Austin\", state: \"TX\" },\n avatarUrl: null,\n activityType: \"Page Views\",\n targetName: \"Viewed product catalog (3 pages)\",\n timestamp: minutesAgo(90),\n slug: \"page_views\",\n title: \"Page viewed\",\n description: \"Viewed product catalog (3 pages)\",\n readAt: minutesAgo(60),\n urgent: false,\n details: {\n type: \"pageView\",\n resourceName: \"Product catalog\",\n },\n },\n {\n id: 4,\n userName: \"Lisa Park\",\n actor: { type: \"contact\", name: \"Lisa Park\" },\n avatarUrl: null,\n activityType: \"Video Complete\",\n targetName: \"Watched: Getting Started Guide\",\n timestamp: minutesAgo(180),\n slug: \"video_complete\",\n title: \"Video finished\",\n description: \"Watched: Getting Started Guide\",\n readAt: minutesAgo(120),\n urgent: false,\n details: {\n type: \"video\",\n contactName: \"Lisa Park\",\n mediumTitle: \"Getting Started Guide\",\n },\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-activities.preview\";\nimport type { ActivitiesPage } from \"@fluid-app/portal-core/widgets-api\";\n\nexport type {\n Activity,\n ActivitySlug,\n} from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type UseActivitiesData = ActivitiesPage;\n\nexport function useActivities(args?: {\n daysAgo?: number;\n}): UseQueryResult<UseActivitiesData, Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"activities\",\n args?.daysAgo ?? null,\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: ({ signal }) => widgetsApi.fetchActivities(args, signal),\n enabled: !isPreview,\n ...(isPreview && {\n // Omit totalCount entirely (rather than setting it to undefined) so\n // tsconfig's exactOptionalPropertyTypes accepts the placeholder shape.\n placeholderData: {\n activities: PREVIEW_DATA,\n nextCursor: null,\n } satisfies UseActivitiesData,\n }),\n });\n}\n","import { useEffect, useMemo, useState, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n borderColorClasses,\n borderWidthClasses,\n getBorderColorField,\n getBorderRadiusField,\n getBorderWidthField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useActivities, type Activity } from \"../hooks/use-activities\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n describeActor,\n EmptyActivityIcon,\n formatActivityDateHeader,\n formatActivityRelativeTime,\n formatActivityTime,\n getActivityDateKey,\n getActivityIcon,\n} from \"@fluid-app/portal-core/activity-presentation\";\nimport { User } from \"lucide-react\";\n\n// ---------- helpers ----------\n\nconst RELATIVE_TIME_REFRESH_MS = 60_000;\nconst DEFAULT_MAX_ITEMS_TO_SHOW = 6;\nconst MAX_ITEMS_TO_SHOW_LIMIT = 20;\n\n// Window matches the Mobile Recent Activity widget, which reads the same\n// days_ago=7 feed, so a rep sees one number across both surfaces.\nconst RECENT_ACTIVITY_DAYS = 7;\n\n// The Activity screen opens on all activity, not this window, so its feed is a\n// superset of what the chip counts. Same split as mobile, where only the Past\n// tab is windowed.\nconst ACTIVITY_SCREEN_SLUG = \"activity\";\n\nconst getColorCssValue = (color: ColorOptions): string =>\n color === \"transparent\" ? \"transparent\" : `var(--color-${color})`;\n\nconst normalizeMaxItemsToShow = (value: number): number => {\n if (!Number.isFinite(value)) return DEFAULT_MAX_ITEMS_TO_SHOW;\n return Math.min(MAX_ITEMS_TO_SHOW_LIMIT, Math.max(1, Math.floor(value)));\n};\n\n// Suppresses the eyebrow when the admin's title already contains it, so a title\n// of \"Recent Activity\" doesn't render as \"RECENT / Recent Activity\". Compared\n// against the translated eyebrow rather than a literal, or the check would only\n// ever work in English.\nconst shouldRenderEyebrow = (\n showEyebrow: boolean,\n titleText: string,\n eyebrowText: string,\n): boolean =>\n showEyebrow &&\n !titleText.trim().toLowerCase().includes(eyebrowText.trim().toLowerCase());\n\n/**\n * Whether the row has nobody to show a face for. Read off the actor rather than\n * sniffed out of the label, which matched the English \"unknown visitor\" and so\n * decided the avatar correctly in one language of the thirty-four.\n */\nconst hasNoKnownPerson = (activity: Activity): boolean =>\n activity.actor.type !== \"contact\";\n\nconst getInitials = (name: string | undefined): string => {\n if (!name) return \"\";\n const parts = name.trim().split(/\\s+/).slice(0, 2);\n return parts.map((p) => p[0]?.toUpperCase() ?? \"\").join(\"\");\n};\n\n// ---------- avatar ----------\n\ntype AvatarProps = {\n activity: Activity;\n textColor: ColorOptions;\n accentColor: ColorOptions;\n surfaceColor: ColorOptions;\n showTypeBadge: boolean;\n};\n\nfunction Avatar({\n activity,\n textColor,\n accentColor,\n surfaceColor,\n showTypeBadge,\n}: AvatarProps) {\n const { t } = useShellTranslation();\n const TypeIcon = getActivityIcon(activity.slug);\n const { label } = describeActor(activity.actor, t);\n const unknown = hasNoKnownPerson(activity);\n const initials = unknown ? \"\" : getInitials(label);\n // 3-tier fallback: image → initials → person icon. If avatarUrl 404s or\n // fails to decode, flip to the next tier instead of showing a broken image.\n const [failedAvatarUrl, setFailedAvatarUrl] = useState<string | null>(null);\n const avatarUrl = activity.avatarUrl;\n const showImage = Boolean(avatarUrl) && failedAvatarUrl !== avatarUrl;\n\n return (\n <div className=\"relative shrink-0\">\n {showImage ? (\n <img\n src={avatarUrl ?? undefined}\n alt={unknown ? \"\" : label}\n width={36}\n height={36}\n loading=\"lazy\"\n onError={() => setFailedAvatarUrl(avatarUrl)}\n className=\"size-9 rounded-full object-cover\"\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n />\n ) : initials ? (\n <div\n className={`flex size-9 items-center justify-center rounded-full text-[11px] font-bold tracking-[0.04em] text-${textColor}/80`}\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 12%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n {initials}\n </div>\n ) : (\n <div\n className={`flex size-9 items-center justify-center rounded-full`}\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 5%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n <User className={`size-3.5 text-${textColor}/55`} />\n </div>\n )}\n\n {/* Type badge — shows what kind of event, regardless of avatar kind. */}\n {showTypeBadge && (\n <span\n className={`bg-${accentColor} text-${accentColor}-foreground absolute -right-0.5 -bottom-0.5 flex size-4 items-center justify-center rounded-full`}\n style={{\n boxShadow: `0 0 0 2px ${getColorCssValue(surfaceColor)}`,\n }}\n aria-hidden=\"true\"\n >\n <TypeIcon style={{ width: 8, height: 8 }} />\n </span>\n )}\n </div>\n );\n}\n\n// ---------- activity row ----------\n\ntype ActivityRowProps = {\n activity: Activity;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n surfaceColor: ColorOptions;\n showRelativeTime: boolean;\n nowMs: number;\n};\n\nfunction ActivityRow({\n activity,\n accentColor,\n textColor,\n surfaceColor,\n showRelativeTime,\n nowMs,\n}: ActivityRowProps) {\n const { t } = useShellTranslation();\n // Same helper the Activity screen uses, so an anonymous visitor reads and looks\n // the same on both surfaces rather than each wording it its own way.\n const { label, muted } = describeActor(activity.actor, t);\n const timeText = showRelativeTime\n ? formatActivityRelativeTime(activity.timestamp, nowMs)\n : formatActivityTime(activity.timestamp);\n\n const absoluteTooltip = new Date(activity.timestamp).toLocaleString(\"en-US\", {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <li\n role=\"article\"\n className=\"relative flex items-start gap-3 rounded-md p-2\"\n >\n <Avatar\n activity={activity}\n textColor={textColor}\n accentColor={accentColor}\n surfaceColor={surfaceColor}\n showTypeBadge\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex items-baseline gap-2\">\n <p\n className={`min-w-0 flex-1 truncate text-[13px] leading-tight font-semibold text-${textColor}`}\n >\n {activity.activityType}\n </p>\n <span\n title={absoluteTooltip}\n className={`shrink-0 font-mono text-[10px] font-medium tabular-nums text-${textColor}/45`}\n >\n {timeText}\n </span>\n </div>\n <p\n className={`mt-0.5 truncate text-[12px] leading-snug text-${textColor}/65`}\n >\n <span\n className={`font-semibold text-${textColor}/85${muted ? \" italic\" : \"\"}`}\n >\n {label}\n </span>\n {activity.targetName && (\n <>\n <span className={`mx-1 text-${textColor}/35`}>·</span>\n <span>{activity.targetName}</span>\n </>\n )}\n </p>\n </div>\n </li>\n );\n}\n\n// ---------- widget ----------\n\ntype RecentActivityWidgetProps = ComponentProps<\"div\"> & {\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n maxItemsToShow?: number;\n\n // Polish (additive)\n showTimeline?: boolean;\n showRelativeTime?: boolean;\n showCountChip?: boolean;\n showEyebrow?: boolean;\n};\n\nfunction useRelativeTimeNow(): number {\n const [nowMs, setNowMs] = useState(() => Date.now());\n\n useEffect(() => {\n const timer = window.setInterval(() => {\n setNowMs(Date.now());\n }, RELATIVE_TIME_REFRESH_MS);\n\n return () => window.clearInterval(timer);\n }, []);\n\n return nowMs;\n}\n\nexport function RecentActivityWidget({\n titleEnabled = true,\n titleText = \"Activity\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n background = { type: \"solid\", color: \"background\" },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"thin\",\n borderColor = \"muted\",\n\n maxItemsToShow = 6,\n\n // showTimeline is intentionally not destructured. The spine it once\n // controlled is no longer rendered. The prop stays on the type so saved\n // widget configs don't fail schema validation.\n showRelativeTime = true,\n showCountChip = true,\n showEyebrow = true,\n\n className,\n onClick: onClickProp,\n ...props\n}: RecentActivityWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n // Rep-facing copy reads the same shell keys the Activity screen does, so the two\n // surfaces cannot drift. The untranslated strings further down are builder field\n // labels and descriptions, which the editor shows an admin rather than a rep.\n const { t } = useShellTranslation();\n\n // Absent in the builder preview, which is how the preview stays inert.\n const { onNavigate } = useWidgetInteraction();\n // The Activity screen is tenant-flagged (PORTAL_ACTIVITY_SCREEN). Without it\n // the widget is a plain summary again: no click-through to offer.\n const { data: store } = useOptionalStore();\n const canNavigate =\n Boolean(onNavigate) && store?.activity_screen_enabled === true;\n\n const goToActivityScreen = () => {\n if (!canNavigate) return;\n onNavigate?.(ACTIVITY_SCREEN_SLUG);\n };\n\n // Clicking anywhere on the card navigates, but the card is not itself a\n // control — the \"View all\" button below is, so keyboard and screen-reader\n // users get a real target without nesting interactive elements.\n const handleRootClick = (event: React.MouseEvent<HTMLDivElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n goToActivityScreen();\n };\n\n const { data, isLoading, isError } = useActivities({\n daysAgo: RECENT_ACTIVITY_DAYS,\n });\n // Stabilize the empty-fallback reference so downstream `useMemo` deps don't\n // see a fresh `[]` on every render.\n const activities = useMemo(() => data?.activities ?? [], [data]);\n const windowedTotal = data?.totalCount;\n const nowMs = useRelativeTimeNow();\n const maxVisibleItems = normalizeMaxItemsToShow(maxItemsToShow);\n const dayLabels = useMemo(\n () => ({\n today: t(\"activity_date_today\"),\n yesterday: t(\"activity_date_yesterday\"),\n }),\n [t],\n );\n\n const activitiesToShow = useMemo(() => {\n if (activities.length === 0)\n return [] as { date: string; items: Activity[] }[];\n const groups = new Map<string, Activity[]>();\n for (const activity of activities.slice(0, maxVisibleItems)) {\n const key = getActivityDateKey(activity.timestamp);\n const existing = groups.get(key);\n if (existing) existing.push(activity);\n else groups.set(key, [activity]);\n }\n return Array.from(groups.entries()).map(([key, items]) => ({\n // `key` is only a defensive fallback; every group is created with at\n // least one activity, so the item timestamp is what normally labels it.\n date: formatActivityDateHeader(\n items[0]?.timestamp ?? key,\n nowMs,\n dayLabels,\n ),\n items,\n }));\n }, [activities, maxVisibleItems, nowMs, dayLabels]);\n\n // Prefer the server total. Fall back to the visible list length when the\n // adapter does not return one, so the widget keeps working before every\n // data path returns a count.\n const totalCount =\n windowedTotal ?? Math.min(activities.length, maxVisibleItems);\n\n return (\n <div\n onClick={canNavigate || onClickProp ? handleRootClick : undefined}\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${canNavigate ? \"cursor-pointer\" : \"\"} ${className ?? \"\"}`}\n style={{\n backgroundImage,\n // Soft ambient lift derived from theme tokens. The configured border\n // props own the crisp outline so saved border settings stay intact.\n boxShadow: `0 1px 2px color-mix(in oklch, var(--color-foreground) 4%, transparent), 0 14px 32px -20px color-mix(in oklch, var(--color-foreground) 14%, transparent)`,\n }}\n {...props}\n >\n <div className={`p-${padding} flex flex-col`}>\n {/* Header */}\n {titleEnabled && titleText && (\n <div className=\"mb-4 flex items-end justify-between gap-3\">\n <div className=\"flex min-w-0 flex-col\">\n {shouldRenderEyebrow(\n showEyebrow,\n titleText,\n t(\"activity_widget_eyebrow\"),\n ) && (\n <span\n className={`text-[10px] font-bold tracking-[0.2em] uppercase text-${textColor}/55`}\n >\n {t(\"activity_widget_eyebrow\")}\n </span>\n )}\n <h2\n className={`mt-0.5 text-${titleFontSize} leading-tight font-bold tracking-[-0.015em] text-${titleColor}`}\n >\n {titleText}\n </h2>\n <span\n className={`mt-0.5 text-xs font-medium text-${textColor}/60`}\n >\n {t(\"activity_widget_window\", { days: RECENT_ACTIVITY_DAYS })}\n </span>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {!isLoading && !isError && showCountChip && totalCount > 0 && (\n <span\n className={`inline-flex shrink-0 items-center gap-1.5 rounded-full bg-${accentColor}/10 px-2 py-1 text-[10px] font-bold tracking-[0.06em] text-${accentColor}`}\n >\n <span\n aria-hidden=\"true\"\n className={`size-1.5 rounded-full bg-${accentColor}`}\n />\n {t(\"activity_widget_updates\", { count: totalCount })}\n </span>\n )}\n {canNavigate && (\n <button\n type=\"button\"\n onClick={(event) => {\n // The card handles clicks too; stop here so one click is\n // one navigation.\n event.stopPropagation();\n goToActivityScreen();\n }}\n className={`shrink-0 rounded-md px-1.5 py-1 text-[11px] font-bold text-${accentColor} hover:bg-${accentColor}/10 focus-visible:ring-${accentColor} focus-visible:ring-2 focus-visible:outline-none`}\n >\n {t(\"activity_view_all\")}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* States */}\n {isLoading ? (\n <ActivitySkeleton textColor={textColor} rowCount={maxVisibleItems} />\n ) : isError ? (\n <ErrorState />\n ) : activities.length === 0 ? (\n <EmptyState textColor={textColor} accentColor={accentColor} />\n ) : (\n /* Feed */\n <div role=\"feed\" className=\"flex flex-col gap-3\">\n {activitiesToShow.map((group, groupIdx) => (\n <section\n key={`${group.date}-${groupIdx}`}\n className=\"flex flex-col gap-1\"\n >\n <header className=\"flex items-center gap-2 px-2\">\n <span\n className={`text-[10px] font-bold tracking-[0.18em] uppercase text-${textColor}/55`}\n >\n {group.date}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1\"\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n />\n </header>\n\n <ul className=\"relative flex flex-col\">\n {/* No timeline spine. An earlier version drew a single\n line at the avatar column, which the avatars occluded,\n leaving only fragmented stubs between rows. */}\n {group.items.map((activity) => (\n <ActivityRow\n key={activity.id}\n activity={activity}\n accentColor={accentColor}\n textColor={textColor}\n surfaceColor={backgroundColor}\n showRelativeTime={showRelativeTime}\n nowMs={nowMs}\n />\n ))}\n </ul>\n </section>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n// ---------- empty state ----------\n\ntype EmptyStateProps = {\n textColor: ColorOptions;\n accentColor: ColorOptions;\n};\n\nfunction EmptyState({ textColor, accentColor }: EmptyStateProps) {\n const { t } = useShellTranslation();\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 py-10\">\n <div\n className=\"relative flex size-12 items-center justify-center rounded-full\"\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 10%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n >\n <EmptyActivityIcon className={`size-5 text-${accentColor}/80`} />\n </div>\n <div className=\"flex flex-col items-center gap-1\">\n <p className={`text-[13px] font-semibold text-${textColor}/80`}>\n {t(\"activity_empty_title\")}\n </p>\n <p\n className={`max-w-[24ch] text-center text-[11px] leading-snug text-${textColor}/55`}\n >\n {t(\"activity_empty_description\")}\n </p>\n </div>\n </div>\n );\n}\n\n// ---------- skeleton ----------\n\ntype ActivitySkeletonProps = {\n textColor: ColorOptions;\n rowCount: number;\n};\n\nfunction ActivitySkeleton({ textColor, rowCount }: ActivitySkeletonProps) {\n return (\n <div className=\"relative flex flex-col\" aria-busy=\"true\">\n {/* No skeleton spine; the loaded state doesn't draw one either. */}\n {Array.from({ length: rowCount }, (_, i) => i).map((i) => (\n <div key={i} className=\"relative flex items-start gap-3 rounded-md p-2\">\n <div\n className={`size-9 shrink-0 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div\n className={`h-2 w-2/3 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div\n className={`h-2 w-1/2 animate-pulse rounded-full bg-${textColor}/10`}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\n// ---------- schema ----------\n\nexport const recentActivityWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"RecentActivityWidget\",\n displayName: \"Recent Activity Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Title\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Display the title and eyebrow above the feed\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the activity feed\",\n defaultValue: \"Activity\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n {\n key: \"showEyebrow\",\n label: \"Show 'RECENT' Eyebrow\",\n type: \"boolean\",\n description: \"Small uppercase label above the title\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n {\n key: \"showCountChip\",\n label: \"Show Updates Count Chip\",\n type: \"boolean\",\n description: \"Accent pill next to the title showing how many updates\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n\n // Feed\n {\n key: \"maxItemsToShow\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of activity items to display\",\n defaultValue: DEFAULT_MAX_ITEMS_TO_SHOW,\n min: 1,\n max: MAX_ITEMS_TO_SHOW_LIMIT,\n step: 1,\n tab: \"styling\",\n group: \"Feed\",\n },\n {\n key: \"showRelativeTime\",\n label: \"Relative Timestamps\",\n type: \"boolean\",\n description: \"Show 'now / 2m / 1h / 3d' instead of absolute times\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Feed\",\n },\n\n // Design\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: { type: \"solid\", color: \"background\" },\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for activity content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description:\n \"Drives the count chip, type badge, initials avatar, and empty-state icon\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget container\",\n defaultValue: \"thin\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget container\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
1
+ {"version":3,"file":"RecentActivityWidget-zBOY0c_B.cjs","names":["useWidgetsApi","useWidgetPreviewContext","useDataSourceRegistryConfig","useShellTranslation","getActivityIcon","describeActor","User","formatActivityRelativeTime","formatActivityTime","useWidgetInteraction","useOptionalStore","getActivityDateKey","formatActivityDateHeader","borderWidthClasses","borderColorClasses","ErrorState","EmptyActivityIcon","getFontSizeField","getColorField","getPaddingField","getBorderRadiusField","getBorderWidthField","getBorderColorField"],"sources":["../../widgets/src/hooks/use-activities.preview.ts","../../widgets/src/hooks/use-activities.ts","../../widgets/src/widgets/RecentActivityWidget.tsx"],"sourcesContent":["import type { Activity } from \"@fluid-app/portal-core/widgets-api-types\";\n\nconst now = new Date();\n\nfunction minutesAgo(minutes: number): string {\n return new Date(now.getTime() - minutes * 60_000).toISOString();\n}\n\nexport const PREVIEW_DATA: Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n actor: { type: \"contact\", name: \"Sarah Johnson\" },\n avatarUrl: null,\n activityType: \"Order Placed\",\n targetName: \"Wellness Starter Kit\",\n timestamp: minutesAgo(12),\n slug: \"order_placed\",\n title: \"New order placed\",\n description: \"Wellness Starter Kit\",\n readAt: null,\n urgent: true,\n details: {\n type: \"order\",\n contactName: \"Sarah Johnson\",\n orderTotal: \"129.99\",\n },\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n actor: { type: \"contact\", name: \"Mike Chen\" },\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Signed up from Instagram link\",\n timestamp: minutesAgo(45),\n slug: \"new_lead\",\n title: \"New lead\",\n description: \"Signed up from Instagram link\",\n readAt: null,\n urgent: true,\n details: {\n type: \"contactLead\",\n contactName: \"Mike Chen\",\n leadType: \"instagram\",\n },\n },\n {\n id: 3,\n userName: \"Visitor from Austin, TX\",\n // A real visitor, so the preview exercises the muted, translated treatment\n // rather than showing contact styling under a visitor's label.\n actor: { type: \"visitor\", city: \"Austin\", state: \"TX\" },\n avatarUrl: null,\n activityType: \"Page Views\",\n targetName: \"Viewed product catalog (3 pages)\",\n timestamp: minutesAgo(90),\n slug: \"page_views\",\n title: \"Page viewed\",\n description: \"Viewed product catalog (3 pages)\",\n readAt: minutesAgo(60),\n urgent: false,\n details: {\n type: \"pageView\",\n resourceName: \"Product catalog\",\n },\n },\n {\n id: 4,\n userName: \"Lisa Park\",\n actor: { type: \"contact\", name: \"Lisa Park\" },\n avatarUrl: null,\n activityType: \"Video Complete\",\n targetName: \"Watched: Getting Started Guide\",\n timestamp: minutesAgo(180),\n slug: \"video_complete\",\n title: \"Video finished\",\n description: \"Watched: Getting Started Guide\",\n readAt: minutesAgo(120),\n urgent: false,\n details: {\n type: \"video\",\n contactName: \"Lisa Park\",\n mediumTitle: \"Getting Started Guide\",\n },\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-activities.preview\";\nimport type { ActivitiesPage } from \"@fluid-app/portal-core/widgets-api\";\n\nexport type {\n Activity,\n ActivitySlug,\n} from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type UseActivitiesData = ActivitiesPage;\n\nexport function useActivities(args?: {\n daysAgo?: number;\n}): UseQueryResult<UseActivitiesData, Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"activities\",\n args?.daysAgo ?? null,\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: ({ signal }) => widgetsApi.fetchActivities(args, signal),\n enabled: !isPreview,\n ...(isPreview && {\n // Omit totalCount entirely (rather than setting it to undefined) so\n // tsconfig's exactOptionalPropertyTypes accepts the placeholder shape.\n placeholderData: {\n activities: PREVIEW_DATA,\n nextCursor: null,\n } satisfies UseActivitiesData,\n }),\n });\n}\n","import { useEffect, useMemo, useState, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n borderColorClasses,\n borderWidthClasses,\n getBorderColorField,\n getBorderRadiusField,\n getBorderWidthField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useActivities, type Activity } from \"../hooks/use-activities\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n describeActor,\n EmptyActivityIcon,\n formatActivityDateHeader,\n formatActivityRelativeTime,\n formatActivityTime,\n getActivityDateKey,\n getActivityIcon,\n} from \"@fluid-app/portal-core/activity-presentation\";\nimport { User } from \"lucide-react\";\n\n// ---------- helpers ----------\n\nconst RELATIVE_TIME_REFRESH_MS = 60_000;\nconst DEFAULT_MAX_ITEMS_TO_SHOW = 6;\nconst MAX_ITEMS_TO_SHOW_LIMIT = 20;\n\n// Window matches the Mobile Recent Activity widget, which reads the same\n// days_ago=7 feed, so a rep sees one number across both surfaces.\nconst RECENT_ACTIVITY_DAYS = 7;\n\n// The Activity screen opens on all activity, not this window, so its feed is a\n// superset of what the chip counts. Same split as mobile, where only the Past\n// tab is windowed.\nconst ACTIVITY_SCREEN_SLUG = \"activity\";\n\nconst getColorCssValue = (color: ColorOptions): string =>\n color === \"transparent\" ? \"transparent\" : `var(--color-${color})`;\n\nconst normalizeMaxItemsToShow = (value: number): number => {\n if (!Number.isFinite(value)) return DEFAULT_MAX_ITEMS_TO_SHOW;\n return Math.min(MAX_ITEMS_TO_SHOW_LIMIT, Math.max(1, Math.floor(value)));\n};\n\n// Suppresses the eyebrow when the admin's title already contains it, so a title\n// of \"Recent Activity\" doesn't render as \"RECENT / Recent Activity\". Compared\n// against the translated eyebrow rather than a literal, or the check would only\n// ever work in English.\nconst shouldRenderEyebrow = (\n showEyebrow: boolean,\n titleText: string,\n eyebrowText: string,\n): boolean =>\n showEyebrow &&\n !titleText.trim().toLowerCase().includes(eyebrowText.trim().toLowerCase());\n\n/**\n * Whether the row has nobody to show a face for. Read off the actor rather than\n * sniffed out of the label, which matched the English \"unknown visitor\" and so\n * decided the avatar correctly in one language of the thirty-four.\n */\nconst hasNoKnownPerson = (activity: Activity): boolean =>\n activity.actor.type !== \"contact\";\n\nconst getInitials = (name: string | undefined): string => {\n if (!name) return \"\";\n const parts = name.trim().split(/\\s+/).slice(0, 2);\n return parts.map((p) => p[0]?.toUpperCase() ?? \"\").join(\"\");\n};\n\n// ---------- avatar ----------\n\ntype AvatarProps = {\n activity: Activity;\n textColor: ColorOptions;\n accentColor: ColorOptions;\n surfaceColor: ColorOptions;\n showTypeBadge: boolean;\n};\n\nfunction Avatar({\n activity,\n textColor,\n accentColor,\n surfaceColor,\n showTypeBadge,\n}: AvatarProps) {\n const { t } = useShellTranslation();\n const TypeIcon = getActivityIcon(activity.slug);\n const { label } = describeActor(activity.actor, t);\n const unknown = hasNoKnownPerson(activity);\n const initials = unknown ? \"\" : getInitials(label);\n // 3-tier fallback: image → initials → person icon. If avatarUrl 404s or\n // fails to decode, flip to the next tier instead of showing a broken image.\n const [failedAvatarUrl, setFailedAvatarUrl] = useState<string | null>(null);\n const avatarUrl = activity.avatarUrl;\n const showImage = Boolean(avatarUrl) && failedAvatarUrl !== avatarUrl;\n\n return (\n <div className=\"relative shrink-0\">\n {showImage ? (\n <img\n src={avatarUrl ?? undefined}\n alt={unknown ? \"\" : label}\n width={36}\n height={36}\n loading=\"lazy\"\n onError={() => setFailedAvatarUrl(avatarUrl)}\n className=\"size-9 rounded-full object-cover\"\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n />\n ) : initials ? (\n <div\n className={`flex size-9 items-center justify-center rounded-full text-[11px] font-bold tracking-[0.04em] text-${textColor}/80`}\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 12%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n {initials}\n </div>\n ) : (\n <div\n className={`flex size-9 items-center justify-center rounded-full`}\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 5%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 10%, transparent)`,\n }}\n aria-label={label}\n >\n <User className={`size-3.5 text-${textColor}/55`} />\n </div>\n )}\n\n {/* Type badge — shows what kind of event, regardless of avatar kind. */}\n {showTypeBadge && (\n <span\n className={`bg-${accentColor} text-${accentColor}-foreground absolute -right-0.5 -bottom-0.5 flex size-4 items-center justify-center rounded-full`}\n style={{\n boxShadow: `0 0 0 2px ${getColorCssValue(surfaceColor)}`,\n }}\n aria-hidden=\"true\"\n >\n <TypeIcon style={{ width: 8, height: 8 }} />\n </span>\n )}\n </div>\n );\n}\n\n// ---------- activity row ----------\n\ntype ActivityRowProps = {\n activity: Activity;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n surfaceColor: ColorOptions;\n showRelativeTime: boolean;\n nowMs: number;\n};\n\nfunction ActivityRow({\n activity,\n accentColor,\n textColor,\n surfaceColor,\n showRelativeTime,\n nowMs,\n}: ActivityRowProps) {\n const { t } = useShellTranslation();\n // Same helper the Activity screen uses, so an anonymous visitor reads and looks\n // the same on both surfaces rather than each wording it its own way.\n const { label, muted } = describeActor(activity.actor, t);\n const timeText = showRelativeTime\n ? formatActivityRelativeTime(activity.timestamp, nowMs)\n : formatActivityTime(activity.timestamp);\n\n const absoluteTooltip = new Date(activity.timestamp).toLocaleString(\"en-US\", {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <li\n role=\"article\"\n className=\"relative flex items-start gap-3 rounded-md p-2\"\n >\n <Avatar\n activity={activity}\n textColor={textColor}\n accentColor={accentColor}\n surfaceColor={surfaceColor}\n showTypeBadge\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex items-baseline gap-2\">\n <p\n className={`min-w-0 flex-1 truncate text-[13px] leading-tight font-semibold text-${textColor}`}\n >\n {activity.activityType}\n </p>\n <span\n title={absoluteTooltip}\n className={`shrink-0 font-mono text-[10px] font-medium tabular-nums text-${textColor}/45`}\n >\n {timeText}\n </span>\n </div>\n <p\n className={`mt-0.5 truncate text-[12px] leading-snug text-${textColor}/65`}\n >\n <span\n className={`font-semibold text-${textColor}/85${muted ? \" italic\" : \"\"}`}\n >\n {label}\n </span>\n {activity.targetName && (\n <>\n <span className={`mx-1 text-${textColor}/35`}>·</span>\n <span>{activity.targetName}</span>\n </>\n )}\n </p>\n </div>\n </li>\n );\n}\n\n// ---------- widget ----------\n\ntype RecentActivityWidgetProps = ComponentProps<\"div\"> & {\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n maxItemsToShow?: number;\n\n // Polish (additive)\n showTimeline?: boolean;\n showRelativeTime?: boolean;\n showCountChip?: boolean;\n showEyebrow?: boolean;\n};\n\nfunction useRelativeTimeNow(): number {\n const [nowMs, setNowMs] = useState(() => Date.now());\n\n useEffect(() => {\n const timer = window.setInterval(() => {\n setNowMs(Date.now());\n }, RELATIVE_TIME_REFRESH_MS);\n\n return () => window.clearInterval(timer);\n }, []);\n\n return nowMs;\n}\n\nexport function RecentActivityWidget({\n titleEnabled = true,\n titleText = \"Activity\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n background = { type: \"solid\", color: \"background\" },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"thin\",\n borderColor = \"muted\",\n\n maxItemsToShow = 6,\n\n // showTimeline is intentionally not destructured. The spine it once\n // controlled is no longer rendered. The prop stays on the type so saved\n // widget configs don't fail schema validation.\n showRelativeTime = true,\n showCountChip = true,\n showEyebrow = true,\n\n className,\n onClick: onClickProp,\n ...props\n}: RecentActivityWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n // Rep-facing copy reads the same shell keys the Activity screen does, so the two\n // surfaces cannot drift. The untranslated strings further down are builder field\n // labels and descriptions, which the editor shows an admin rather than a rep.\n const { t } = useShellTranslation();\n\n // Absent in the builder preview, which is how the preview stays inert.\n const { onNavigate } = useWidgetInteraction();\n // The Activity screen is tenant-flagged (PORTAL_ACTIVITY_SCREEN). Without it\n // the widget is a plain summary again: no click-through to offer.\n const { data: store } = useOptionalStore();\n const canNavigate =\n Boolean(onNavigate) && store?.activity_screen_enabled === true;\n\n const goToActivityScreen = () => {\n if (!canNavigate) return;\n onNavigate?.(ACTIVITY_SCREEN_SLUG);\n };\n\n // Clicking anywhere on the card navigates, but the card is not itself a\n // control — the \"View all\" button below is, so keyboard and screen-reader\n // users get a real target without nesting interactive elements.\n const handleRootClick = (event: React.MouseEvent<HTMLDivElement>) => {\n onClickProp?.(event);\n if (event.defaultPrevented) return;\n goToActivityScreen();\n };\n\n const { data, isLoading, isError } = useActivities({\n daysAgo: RECENT_ACTIVITY_DAYS,\n });\n // Stabilize the empty-fallback reference so downstream `useMemo` deps don't\n // see a fresh `[]` on every render.\n const activities = useMemo(() => data?.activities ?? [], [data]);\n const windowedTotal = data?.totalCount;\n const nowMs = useRelativeTimeNow();\n const maxVisibleItems = normalizeMaxItemsToShow(maxItemsToShow);\n const dayLabels = useMemo(\n () => ({\n today: t(\"activity_date_today\"),\n yesterday: t(\"activity_date_yesterday\"),\n }),\n [t],\n );\n\n const activitiesToShow = useMemo(() => {\n if (activities.length === 0)\n return [] as { date: string; items: Activity[] }[];\n const groups = new Map<string, Activity[]>();\n for (const activity of activities.slice(0, maxVisibleItems)) {\n const key = getActivityDateKey(activity.timestamp);\n const existing = groups.get(key);\n if (existing) existing.push(activity);\n else groups.set(key, [activity]);\n }\n return Array.from(groups.entries()).map(([key, items]) => ({\n // `key` is only a defensive fallback; every group is created with at\n // least one activity, so the item timestamp is what normally labels it.\n date: formatActivityDateHeader(\n items[0]?.timestamp ?? key,\n nowMs,\n dayLabels,\n ),\n items,\n }));\n }, [activities, maxVisibleItems, nowMs, dayLabels]);\n\n // Prefer the server total. Fall back to the visible list length when the\n // adapter does not return one, so the widget keeps working before every\n // data path returns a count.\n const totalCount =\n windowedTotal ?? Math.min(activities.length, maxVisibleItems);\n\n return (\n <div\n onClick={canNavigate || onClickProp ? handleRootClick : undefined}\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${canNavigate ? \"cursor-pointer\" : \"\"} ${className ?? \"\"}`}\n style={{\n backgroundImage,\n // Soft ambient lift derived from theme tokens. The configured border\n // props own the crisp outline so saved border settings stay intact.\n boxShadow: `0 1px 2px color-mix(in oklch, var(--color-foreground) 4%, transparent), 0 14px 32px -20px color-mix(in oklch, var(--color-foreground) 14%, transparent)`,\n }}\n {...props}\n >\n <div className={`p-${padding} flex flex-col`}>\n {/* Header */}\n {titleEnabled && titleText && (\n <div className=\"mb-4 flex items-end justify-between gap-3\">\n <div className=\"flex min-w-0 flex-col\">\n {shouldRenderEyebrow(\n showEyebrow,\n titleText,\n t(\"activity_widget_eyebrow\"),\n ) && (\n <span\n className={`text-[10px] font-bold tracking-[0.2em] uppercase text-${textColor}/55`}\n >\n {t(\"activity_widget_eyebrow\")}\n </span>\n )}\n <h2\n className={`mt-0.5 text-${titleFontSize} leading-tight font-bold tracking-[-0.015em] text-${titleColor}`}\n >\n {titleText}\n </h2>\n <span\n className={`mt-0.5 text-xs font-medium text-${textColor}/60`}\n >\n {t(\"activity_widget_window\", { days: RECENT_ACTIVITY_DAYS })}\n </span>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {!isLoading && !isError && showCountChip && totalCount > 0 && (\n <span\n className={`inline-flex shrink-0 items-center gap-1.5 rounded-full bg-${accentColor}/10 px-2 py-1 text-[10px] font-bold tracking-[0.06em] text-${accentColor}`}\n >\n <span\n aria-hidden=\"true\"\n className={`size-1.5 rounded-full bg-${accentColor}`}\n />\n {t(\"activity_widget_updates\", { count: totalCount })}\n </span>\n )}\n {canNavigate && (\n <button\n type=\"button\"\n onClick={(event) => {\n // The card handles clicks too; stop here so one click is\n // one navigation.\n event.stopPropagation();\n goToActivityScreen();\n }}\n className={`shrink-0 rounded-md px-1.5 py-1 text-[11px] font-bold text-${accentColor} hover:bg-${accentColor}/10 focus-visible:ring-${accentColor} focus-visible:ring-2 focus-visible:outline-none`}\n >\n {t(\"activity_view_all\")}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* States */}\n {isLoading ? (\n <ActivitySkeleton textColor={textColor} rowCount={maxVisibleItems} />\n ) : isError ? (\n <ErrorState />\n ) : activities.length === 0 ? (\n <EmptyState textColor={textColor} accentColor={accentColor} />\n ) : (\n /* Feed */\n <div role=\"feed\" className=\"flex flex-col gap-3\">\n {activitiesToShow.map((group, groupIdx) => (\n <section\n key={`${group.date}-${groupIdx}`}\n className=\"flex flex-col gap-1\"\n >\n <header className=\"flex items-center gap-2 px-2\">\n <span\n className={`text-[10px] font-bold tracking-[0.18em] uppercase text-${textColor}/55`}\n >\n {group.date}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1\"\n style={{\n background: `color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n />\n </header>\n\n <ul className=\"relative flex flex-col\">\n {/* No timeline spine. An earlier version drew a single\n line at the avatar column, which the avatars occluded,\n leaving only fragmented stubs between rows. */}\n {group.items.map((activity) => (\n <ActivityRow\n key={activity.id}\n activity={activity}\n accentColor={accentColor}\n textColor={textColor}\n surfaceColor={backgroundColor}\n showRelativeTime={showRelativeTime}\n nowMs={nowMs}\n />\n ))}\n </ul>\n </section>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\n// ---------- empty state ----------\n\ntype EmptyStateProps = {\n textColor: ColorOptions;\n accentColor: ColorOptions;\n};\n\nfunction EmptyState({ textColor, accentColor }: EmptyStateProps) {\n const { t } = useShellTranslation();\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 px-4 py-10\">\n <div\n className=\"relative flex size-12 items-center justify-center rounded-full\"\n style={{\n background: `color-mix(in oklch, var(--color-${accentColor}) 10%, transparent)`,\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${textColor}) 8%, transparent)`,\n }}\n >\n <EmptyActivityIcon className={`size-5 text-${accentColor}/80`} />\n </div>\n <div className=\"flex flex-col items-center gap-1\">\n <p className={`text-[13px] font-semibold text-${textColor}/80`}>\n {t(\"activity_empty_title\")}\n </p>\n <p\n className={`max-w-[24ch] text-center text-[11px] leading-snug text-${textColor}/55`}\n >\n {t(\"activity_empty_description\")}\n </p>\n </div>\n </div>\n );\n}\n\n// ---------- skeleton ----------\n\ntype ActivitySkeletonProps = {\n textColor: ColorOptions;\n rowCount: number;\n};\n\nfunction ActivitySkeleton({ textColor, rowCount }: ActivitySkeletonProps) {\n return (\n <div className=\"relative flex flex-col\" aria-busy=\"true\">\n {/* No skeleton spine; the loaded state doesn't draw one either. */}\n {Array.from({ length: rowCount }, (_, i) => i).map((i) => (\n <div key={i} className=\"relative flex items-start gap-3 rounded-md p-2\">\n <div\n className={`size-9 shrink-0 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <div\n className={`h-2 w-2/3 animate-pulse rounded-full bg-${textColor}/10`}\n />\n <div\n className={`h-2 w-1/2 animate-pulse rounded-full bg-${textColor}/10`}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\n// ---------- schema ----------\n\nexport const recentActivityWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"RecentActivityWidget\",\n displayName: \"Recent Activity Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Title\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Display the title and eyebrow above the feed\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the activity feed\",\n defaultValue: \"Activity\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n {\n key: \"showEyebrow\",\n label: \"Show 'RECENT' Eyebrow\",\n type: \"boolean\",\n description: \"Small uppercase label above the title\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n {\n key: \"showCountChip\",\n label: \"Show Updates Count Chip\",\n type: \"boolean\",\n description: \"Accent pill next to the title showing how many updates\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n\n // Feed\n {\n key: \"maxItemsToShow\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of activity items to display\",\n defaultValue: DEFAULT_MAX_ITEMS_TO_SHOW,\n min: 1,\n max: MAX_ITEMS_TO_SHOW_LIMIT,\n step: 1,\n tab: \"styling\",\n group: \"Feed\",\n },\n {\n key: \"showRelativeTime\",\n label: \"Relative Timestamps\",\n type: \"boolean\",\n description: \"Show 'now / 2m / 1h / 3d' instead of absolute times\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Feed\",\n },\n\n // Design\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: { type: \"solid\", color: \"background\" },\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for activity content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description:\n \"Drives the count chip, type badge, initials avatar, and empty-state icon\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget container\",\n defaultValue: \"thin\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget container\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  require("./chunk-9hOWP6kD.cjs");
2
2
  const require_MobileBottomSheet = require("./MobileBottomSheet-DDGmDuV6.cjs");
3
- const require_WidgetInteractionContext = require("./WidgetInteractionContext-Bjy4P_YP.cjs");
3
+ const require_WidgetInteractionContext = require("./WidgetInteractionContext-D9dBJ-39.cjs");
4
4
  const require_SearchSort = require("./SearchSort-BFE4vK5I.cjs");
5
5
  const require_registries = require("./registries-MpWTUak_.cjs");
6
6
  const require_preview_context = require("./preview-context-DDYz757l.cjs");
@@ -705,4 +705,4 @@ Object.defineProperty(exports, "shopWidgetPropertySchema", {
705
705
  }
706
706
  });
707
707
 
708
- //# sourceMappingURL=ShopWidget-C5hjVwsY.cjs.map
708
+ //# sourceMappingURL=ShopWidget-CCITGTSs.cjs.map