@agent-native/core 0.154.5 → 0.157.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/account-health/SKILL.md +76 -0
  3. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
  4. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
  5. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
  6. package/corpus/templates/analytics/AGENTS.md +3 -0
  7. package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
  8. package/corpus/templates/analytics/actions/bigquery.ts +1 -1
  9. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
  10. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  11. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
  12. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
  13. package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
  14. package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
  15. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
  16. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
  17. package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
  18. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
  19. package/corpus/templates/assets/app/i18n-data.ts +21 -1
  20. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
  21. package/corpus/templates/calendar/AGENTS.md +2 -0
  22. package/corpus/templates/calendar/DEVELOPING.md +4 -4
  23. package/corpus/templates/calendar/actions/get-settings.ts +4 -11
  24. package/corpus/templates/calendar/actions/update-availability.ts +15 -4
  25. package/corpus/templates/calendar/actions/update-settings.ts +15 -4
  26. package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
  27. package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
  28. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
  29. package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
  30. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
  31. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
  32. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
  33. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
  34. package/corpus/templates/calendar/app/i18n-data.ts +30 -0
  35. package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
  36. package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
  37. package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
  38. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
  39. package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
  40. package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
  41. package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
  42. package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
  43. package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
  44. package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
  45. package/corpus/templates/calendar/shared/api.ts +1 -0
  46. package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
  47. package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
  48. package/corpus/templates/calendar/shared/settings.ts +44 -0
  49. package/corpus/templates/clips/AGENTS.md +2 -0
  50. package/corpus/templates/clips/actions/add-comment.ts +5 -2
  51. package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
  52. package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
  53. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
  54. package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
  55. package/corpus/templates/clips/actions/update-comment.ts +9 -2
  56. package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
  57. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
  58. package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
  59. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
  60. package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
  61. package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
  62. package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
  63. package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
  64. package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
  65. package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
  66. package/corpus/templates/clips/app/root.tsx +2 -1
  67. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
  68. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
  69. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
  70. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
  71. package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
  72. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
  73. package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
  74. package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
  75. package/corpus/templates/clips/desktop/src/app.tsx +116 -19
  76. package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
  77. package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
  78. package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
  79. package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
  80. package/corpus/templates/clips/desktop/src/styles.css +117 -0
  81. package/corpus/templates/clips/server/db/index.ts +10 -0
  82. package/corpus/templates/clips/server/db/schema.ts +1 -0
  83. package/corpus/templates/clips/server/lib/recordings.ts +3 -1
  84. package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
  85. package/corpus/templates/clips/server/plugins/db.ts +5 -0
  86. package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
  87. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
  88. package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
  89. package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
  90. package/corpus/templates/content/actions/add-comment.ts +2 -1
  91. package/corpus/templates/content/actions/update-comment.ts +1 -1
  92. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
  93. package/corpus/templates/design/actions/generate-design.ts +10 -7
  94. package/corpus/templates/design/actions/present-design-variants.ts +35 -6
  95. package/corpus/templates/design/actions/run-design-audit.ts +33 -0
  96. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
  97. package/corpus/templates/design/shared/design-review.ts +1 -0
  98. package/corpus/templates/design/shared/html-integrity.ts +66 -0
  99. package/corpus/templates/dispatch/.env.example +5 -0
  100. package/corpus/templates/dispatch/AGENTS.md +24 -19
  101. package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
  102. package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
  103. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
  104. package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
  105. package/corpus/templates/factory/AGENTS.md +5 -1
  106. package/corpus/templates/factory/README.md +23 -0
  107. package/corpus/templates/factory/actions/view-screen.ts +17 -0
  108. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
  109. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
  110. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
  111. package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
  112. package/corpus/templates/factory/app/routes/factory.tsx +41 -0
  113. package/corpus/templates/factory/package.json +1 -0
  114. package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
  115. package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
  116. package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
  117. package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
  118. package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
  119. package/corpus/templates/mail/vite.config.ts +7 -0
  120. package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
  121. package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
  122. package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
  123. package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
  124. package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
  125. package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
  126. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
  127. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
  128. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
  129. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
  130. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
  131. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
  132. package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
  133. package/corpus/templates/slides/app/global.css +7 -40
  134. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  135. package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
  136. package/dist/agent/index.d.ts +1 -1
  137. package/dist/agent/production-agent.d.ts +30 -0
  138. package/dist/agent/production-agent.js +105 -9
  139. package/dist/agent/thread-data-builder.js +17 -1
  140. package/dist/agent/types.d.ts +9 -0
  141. package/dist/cli/skills-content/help.js +6 -4
  142. package/dist/cli/skills.js +17 -2
  143. package/dist/cli/workspacify.d.ts +5 -0
  144. package/dist/cli/workspacify.js +65 -8
  145. package/dist/client/AgentPanel.d.ts +5 -0
  146. package/dist/client/AgentPanel.js +32 -13
  147. package/dist/client/AssistantChat.d.ts +36 -1
  148. package/dist/client/AssistantChat.js +175 -110
  149. package/dist/client/MultiTabAssistantChat.js +44 -27
  150. package/dist/client/active-run-state.d.ts +14 -1
  151. package/dist/client/active-run-state.js +0 -0
  152. package/dist/client/agent-chat-adapter.js +107 -5
  153. package/dist/client/analytics.js +9 -2
  154. package/dist/client/chat/markdown-renderer.js +4 -2
  155. package/dist/client/chat/message-components.d.ts +2 -2
  156. package/dist/client/chat/message-components.js +69 -35
  157. package/dist/client/chat/run-recovery.d.ts +4 -1
  158. package/dist/client/chat/run-recovery.js +62 -30
  159. package/dist/client/chat/tool-call-display.d.ts +12 -3
  160. package/dist/client/chat/tool-call-display.js +79 -40
  161. package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
  162. package/dist/client/chat/widgets/DataChartWidget.js +8 -2
  163. package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
  164. package/dist/client/chat/widgets/DataTableWidget.js +23 -9
  165. package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
  166. package/dist/client/chat-first/apps-rail.js +9 -4
  167. package/dist/client/chat-first/primary-nav.d.ts +2 -1
  168. package/dist/client/chat-first/primary-nav.js +3 -3
  169. package/dist/client/chat-first/types.d.ts +5 -1
  170. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  171. package/dist/client/components/ui/message-scroller.js +7 -3
  172. package/dist/client/composer/runtime-adapters.js +3 -2
  173. package/dist/client/context-xray/ContextMeter.js +5 -1
  174. package/dist/client/context-xray/ContextXRayPanel.js +5 -5
  175. package/dist/client/error-format.d.ts +4 -0
  176. package/dist/client/error-format.js +93 -5
  177. package/dist/client/i18n.js +83 -17
  178. package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
  179. package/dist/client/markdown/InlineMarkdown.js +65 -0
  180. package/dist/client/markdown/index.d.ts +1 -0
  181. package/dist/client/markdown/index.js +1 -0
  182. package/dist/client/observability/ThumbsFeedback.js +10 -8
  183. package/dist/client/review/ReviewThreadPanel.js +2 -1
  184. package/dist/client/run-stream-ownership.d.ts +39 -0
  185. package/dist/client/run-stream-ownership.js +65 -0
  186. package/dist/client/sharing/ShareButton.js +160 -54
  187. package/dist/coding-tools/run-code.js +2 -1
  188. package/dist/coding-tools/sandbox/background.d.ts +1 -0
  189. package/dist/coding-tools/sandbox/background.js +8 -1
  190. package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
  191. package/dist/coding-tools/sandbox/executions-store.js +41 -3
  192. package/dist/collab/awareness.d.ts +2 -2
  193. package/dist/collab/routes.d.ts +1 -1
  194. package/dist/collab/struct-routes.d.ts +1 -1
  195. package/dist/feature-flags/index.d.ts +1 -1
  196. package/dist/feature-flags/index.js +1 -1
  197. package/dist/feature-flags/store.d.ts +10 -0
  198. package/dist/feature-flags/store.js +112 -1
  199. package/dist/guards/no-env-credentials.js +4 -0
  200. package/dist/index.d.ts +2 -2
  201. package/dist/index.js +1 -1
  202. package/dist/integrations/adapters/slack.js +5 -1
  203. package/dist/localization/core-messages/ar-SA.d.ts +3 -0
  204. package/dist/localization/core-messages/ar-SA.js +541 -0
  205. package/dist/localization/core-messages/de-DE.d.ts +3 -0
  206. package/dist/localization/core-messages/de-DE.js +513 -0
  207. package/dist/localization/core-messages/en-US.d.ts +513 -0
  208. package/dist/localization/core-messages/en-US.js +513 -0
  209. package/dist/localization/core-messages/es-ES.d.ts +3 -0
  210. package/dist/localization/core-messages/es-ES.js +520 -0
  211. package/dist/localization/core-messages/fr-FR.d.ts +3 -0
  212. package/dist/localization/core-messages/fr-FR.js +520 -0
  213. package/dist/localization/core-messages/hi-IN.d.ts +3 -0
  214. package/dist/localization/core-messages/hi-IN.js +513 -0
  215. package/dist/localization/core-messages/ja-JP.d.ts +3 -0
  216. package/dist/localization/core-messages/ja-JP.js +506 -0
  217. package/dist/localization/core-messages/ko-KR.d.ts +3 -0
  218. package/dist/localization/core-messages/ko-KR.js +506 -0
  219. package/dist/localization/core-messages/pt-BR.d.ts +3 -0
  220. package/dist/localization/core-messages/pt-BR.js +520 -0
  221. package/dist/localization/core-messages/zh-CN.d.ts +3 -0
  222. package/dist/localization/core-messages/zh-CN.js +506 -0
  223. package/dist/localization/core-messages/zh-TW.d.ts +3 -0
  224. package/dist/localization/core-messages/zh-TW.js +506 -0
  225. package/dist/localization/core-messages.d.ts +524 -0
  226. package/dist/localization/core-messages.js +124 -0
  227. package/dist/localization/default-messages.d.ts +3 -0
  228. package/dist/localization/default-messages.js +3 -0
  229. package/dist/notifications/routes.d.ts +1 -1
  230. package/dist/observability/routes.d.ts +2 -2
  231. package/dist/progress/routes.d.ts +1 -1
  232. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  233. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  234. package/dist/resources/agents.js +40 -5
  235. package/dist/resources/metadata.d.ts +10 -0
  236. package/dist/resources/metadata.js +7 -3
  237. package/dist/review/actions/create-review-comment.js +1 -1
  238. package/dist/review/actions/reply-review-comment.js +1 -1
  239. package/dist/review/actions/resolve-review-thread.js +1 -1
  240. package/dist/secrets/routes.d.ts +6 -6
  241. package/dist/server/action-routes.js +32 -6
  242. package/dist/server/agent-chat/plugin-options.d.ts +7 -2
  243. package/dist/server/agent-chat-plugin.d.ts +10 -0
  244. package/dist/server/agent-chat-plugin.js +144 -41
  245. package/dist/server/agent-discovery.js +14 -3
  246. package/dist/server/agent-run-context.d.ts +7 -1
  247. package/dist/server/agent-run-context.js +9 -2
  248. package/dist/server/agent-teams-run-queue.d.ts +3 -0
  249. package/dist/server/agent-teams.js +38 -9
  250. package/dist/server/core-routes-plugin.js +1 -1
  251. package/dist/server/identity-sso-migrations.d.ts +7 -0
  252. package/dist/server/identity-sso-migrations.js +36 -0
  253. package/dist/server/identity-sso-store.d.ts +3 -2
  254. package/dist/server/identity-sso-store.js +8 -3
  255. package/dist/server/index.d.ts +1 -1
  256. package/dist/server/realtime-token.d.ts +1 -1
  257. package/dist/server/release-migrations.js +4 -0
  258. package/dist/server/request-context.d.ts +7 -0
  259. package/dist/server/request-context.js +15 -0
  260. package/dist/tracking/providers.js +13 -3
  261. package/dist/workspace-files/tool.js +1 -1
  262. package/docs/content/agent-surfaces.mdx +30 -0
  263. package/package.json +3 -2
@@ -107,6 +107,7 @@ interface WeekViewProps {
107
107
  ) => void;
108
108
  onDraftDiscard?: (eventId: string) => void;
109
109
  isLoading?: boolean;
110
+ weekStartsOn?: 0 | 1;
110
111
  }
111
112
 
112
113
  // [startHour, startMin, durationMin, widthPct] per day column (Sun–Sat)
@@ -559,6 +560,7 @@ export const WeekView = memo(function WeekView({
559
560
  onDraftCreate,
560
561
  onDraftDiscard,
561
562
  isLoading = false,
563
+ weekStartsOn = 0,
562
564
  }: WeekViewProps) {
563
565
  const t = useT();
564
566
  const workingLocationLabels = useMemo(
@@ -606,8 +608,14 @@ export const WeekView = memo(function WeekView({
606
608
  }, []);
607
609
 
608
610
  const { prefs } = useViewPreferences();
609
- const weekStart = useMemo(() => startOfWeek(selectedDate), [selectedDate]);
610
- const weekEnd = useMemo(() => endOfWeek(selectedDate), [selectedDate]);
611
+ const weekStart = useMemo(
612
+ () => startOfWeek(selectedDate, { weekStartsOn }),
613
+ [selectedDate, weekStartsOn],
614
+ );
615
+ const weekEnd = useMemo(
616
+ () => endOfWeek(selectedDate, { weekStartsOn }),
617
+ [selectedDate, weekStartsOn],
618
+ );
611
619
  // Stable day/hour arrays — recomputed only when the week or weekend
612
620
  // visibility actually changes, so memoized children (event buttons) don't
613
621
  // see a new array identity on every drag/focus re-render.
@@ -1408,7 +1416,7 @@ export const WeekView = memo(function WeekView({
1408
1416
 
1409
1417
  {/* Skeleton events when loading */}
1410
1418
  {isLoading &&
1411
- WEEK_SKELETONS[dayIndex]?.map(
1419
+ WEEK_SKELETONS[day.getDay()]?.map(
1412
1420
  ([startHour, startMin, duration, widthPct], i) => {
1413
1421
  const topPx =
1414
1422
  ((startHour - START_HOUR) * 60 + startMin) *
@@ -5,6 +5,7 @@ import { openCommandMenu } from "@agent-native/core/client/navigation";
5
5
  import { OrgSwitcher } from "@agent-native/core/client/org";
6
6
  import { FeedbackButton } from "@agent-native/core/client/ui";
7
7
  import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
8
+ import { getWeekdayOrder, getWeekStartsOn } from "@shared/calendar-week";
8
9
  import {
9
10
  IconCalendar,
10
11
  IconSettings,
@@ -77,6 +78,7 @@ import {
77
78
  useRemoveOverlayPerson,
78
79
  useUpdateOverlayPersonColor,
79
80
  } from "@/hooks/use-overlay-people";
81
+ import { useSettings } from "@/hooks/use-settings";
80
82
  import { useViewPreferences } from "@/hooks/use-view-preferences";
81
83
  import {
82
84
  CALENDAR_COLORS,
@@ -200,6 +202,8 @@ function MiniCalendar({
200
202
  }) {
201
203
  const [viewMonth, setViewMonth] = useState(() => startOfMonth(selectedDate));
202
204
  const [pickerOpen, setPickerOpen] = useState(false);
205
+ const { data: settings } = useSettings();
206
+ const weekStartsOn = getWeekStartsOn(settings?.weekStart);
203
207
 
204
208
  // Sync viewMonth when selectedDate changes to a different month
205
209
  useEffect(() => {
@@ -211,8 +215,8 @@ function MiniCalendar({
211
215
  const days = useMemo(() => {
212
216
  const monthStart = startOfMonth(viewMonth);
213
217
  const monthEnd = endOfMonth(viewMonth);
214
- const calStart = startOfWeek(monthStart);
215
- const calEnd = endOfWeek(monthEnd);
218
+ const calStart = startOfWeek(monthStart, { weekStartsOn });
219
+ const calEnd = endOfWeek(monthEnd, { weekStartsOn });
216
220
 
217
221
  const result: Date[] = [];
218
222
  let current = calStart;
@@ -221,9 +225,11 @@ function MiniCalendar({
221
225
  current = addDays(current, 1);
222
226
  }
223
227
  return result;
224
- }, [viewMonth]);
228
+ }, [viewMonth, weekStartsOn]);
225
229
 
226
- const weekdays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
230
+ const weekdays = getWeekdayOrder(weekStartsOn).map(
231
+ (day) => ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"][day],
232
+ );
227
233
 
228
234
  return (
229
235
  <div className="px-3 py-3">
@@ -265,6 +265,9 @@ const enUS = {
265
265
  defaultDurationLabel: "Default event duration (minutes)",
266
266
  defaultDurationHelp:
267
267
  "Default length for new calendar events and booking slots. Booking links can override this per link.",
268
+ weekStartLabel: "Week starts on",
269
+ weekStartSunday: "Sunday - Saturday",
270
+ weekStartMonday: "Monday - Sunday",
268
271
  },
269
272
  eventDialog: {
270
273
  eventUpdated: "Event updated",
@@ -4303,6 +4306,9 @@ const translatedCalendarExtras = {
4303
4306
  defaultDurationLabel: "默认事件时长(分钟)",
4304
4307
  defaultDurationHelp:
4305
4308
  "新日历事件和预约时段的默认长度。预约链接可按链接覆盖此设置。",
4309
+ weekStartLabel: "每周从哪天开始",
4310
+ weekStartSunday: "周日 - 周六",
4311
+ weekStartMonday: "周一 - 周日",
4306
4312
  },
4307
4313
  eventDialog: {
4308
4314
  eventUpdated: "事件已更新",
@@ -4372,6 +4378,9 @@ const translatedCalendarExtras = {
4372
4378
  defaultDurationLabel: "Duración predeterminada del evento (minutos)",
4373
4379
  defaultDurationHelp:
4374
4380
  "Duración predeterminada para eventos nuevos y franjas de reserva. Cada enlace de reserva puede anularla.",
4381
+ weekStartLabel: "La semana empieza el",
4382
+ weekStartSunday: "Domingo - sábado",
4383
+ weekStartMonday: "Lunes - domingo",
4375
4384
  },
4376
4385
  eventDialog: {
4377
4386
  eventUpdated: "Evento actualizado",
@@ -4442,6 +4451,9 @@ const translatedCalendarExtras = {
4442
4451
  defaultDurationLabel: "Durée d'événement par défaut (minutes)",
4443
4452
  defaultDurationHelp:
4444
4453
  "Durée par défaut des nouveaux événements et créneaux de réservation. Chaque lien de réservation peut la remplacer.",
4454
+ weekStartLabel: "La semaine commence le",
4455
+ weekStartSunday: "Dimanche - samedi",
4456
+ weekStartMonday: "Lundi - dimanche",
4445
4457
  },
4446
4458
  eventDialog: {
4447
4459
  eventUpdated: "Événement mis à jour",
@@ -4512,6 +4524,9 @@ const translatedCalendarExtras = {
4512
4524
  defaultDurationLabel: "Standarddauer für Ereignisse (Minuten)",
4513
4525
  defaultDurationHelp:
4514
4526
  "Standardlänge für neue Kalenderereignisse und Buchungsslots. Buchungslinks können sie pro Link überschreiben.",
4527
+ weekStartLabel: "Wochenbeginn",
4528
+ weekStartSunday: "Sonntag - Samstag",
4529
+ weekStartMonday: "Montag - Sonntag",
4515
4530
  },
4516
4531
  eventDialog: {
4517
4532
  eventUpdated: "Ereignis aktualisiert",
@@ -4581,6 +4596,9 @@ const translatedCalendarExtras = {
4581
4596
  defaultDurationLabel: "デフォルトのイベント時間(分)",
4582
4597
  defaultDurationHelp:
4583
4598
  "新しいカレンダーイベントと予約枠のデフォルト時間です。予約リンクごとに上書きできます。",
4599
+ weekStartLabel: "週の開始日",
4600
+ weekStartSunday: "日曜日 - 土曜日",
4601
+ weekStartMonday: "月曜日 - 日曜日",
4584
4602
  },
4585
4603
  eventDialog: {
4586
4604
  eventUpdated: "イベントを更新しました",
@@ -4647,6 +4665,9 @@ const translatedCalendarExtras = {
4647
4665
  defaultDurationLabel: "기본 이벤트 시간(분)",
4648
4666
  defaultDurationHelp:
4649
4667
  "새 캘린더 이벤트와 예약 슬롯의 기본 길이입니다. 예약 링크별로 재정의할 수 있습니다.",
4668
+ weekStartLabel: "주 시작일",
4669
+ weekStartSunday: "일요일 - 토요일",
4670
+ weekStartMonday: "월요일 - 일요일",
4650
4671
  },
4651
4672
  eventDialog: {
4652
4673
  eventUpdated: "이벤트가 업데이트되었습니다",
@@ -4716,6 +4737,9 @@ const translatedCalendarExtras = {
4716
4737
  defaultDurationLabel: "Duração padrão do evento (minutos)",
4717
4738
  defaultDurationHelp:
4718
4739
  "Duração padrão para novos eventos e horários de agendamento. Links de agendamento podem substituir isso por link.",
4740
+ weekStartLabel: "A semana começa no",
4741
+ weekStartSunday: "Domingo - sábado",
4742
+ weekStartMonday: "Segunda-feira - domingo",
4719
4743
  },
4720
4744
  eventDialog: {
4721
4745
  eventUpdated: "Evento atualizado",
@@ -4784,6 +4808,9 @@ const translatedCalendarExtras = {
4784
4808
  defaultDurationLabel: "डिफ़ॉल्ट इवेंट अवधि (मिनट)",
4785
4809
  defaultDurationHelp:
4786
4810
  "नए कैलेंडर इवेंट और बुकिंग स्लॉट की डिफ़ॉल्ट लंबाई। बुकिंग लिंक इसे प्रति लिंक बदल सकते हैं।",
4811
+ weekStartLabel: "सप्ताह की शुरुआत",
4812
+ weekStartSunday: "रविवार - शनिवार",
4813
+ weekStartMonday: "सोमवार - रविवार",
4787
4814
  },
4788
4815
  eventDialog: {
4789
4816
  eventUpdated: "इवेंट अपडेट हो गया",
@@ -4851,6 +4878,9 @@ const translatedCalendarExtras = {
4851
4878
  defaultDurationLabel: "مدة الحدث الافتراضية (بالدقائق)",
4852
4879
  defaultDurationHelp:
4853
4880
  "المدة الافتراضية لأحداث التقويم الجديدة وفتحات الحجز. يمكن لروابط الحجز تجاوزها لكل رابط.",
4881
+ weekStartLabel: "يبدأ الأسبوع يوم",
4882
+ weekStartSunday: "الأحد - السبت",
4883
+ weekStartMonday: "الاثنين - الأحد",
4854
4884
  },
4855
4885
  eventDialog: {
4856
4886
  eventUpdated: "تم تحديث الحدث",
@@ -0,0 +1,53 @@
1
+ import type { DaySchedule, TimeSlot } from "../../shared/api";
2
+
3
+ export const DEFAULT_TIME_SLOT: TimeSlot = {
4
+ start: "09:00",
5
+ end: "17:00",
6
+ };
7
+
8
+ export function getEditableTimeSlots(day: DaySchedule): TimeSlot[] {
9
+ return day.slots.length > 0 ? day.slots : [{ ...DEFAULT_TIME_SLOT }];
10
+ }
11
+
12
+ export function setDayEnabled(day: DaySchedule, enabled: boolean): DaySchedule {
13
+ return {
14
+ ...day,
15
+ enabled,
16
+ slots: enabled ? getEditableTimeSlots(day) : day.slots,
17
+ };
18
+ }
19
+
20
+ export function updateTimeSlot(
21
+ day: DaySchedule,
22
+ slotIndex: number,
23
+ field: "start" | "end",
24
+ value: string,
25
+ ): DaySchedule {
26
+ return {
27
+ ...day,
28
+ slots: getEditableTimeSlots(day).map((slot, index) =>
29
+ index === slotIndex ? { ...slot, [field]: value } : slot,
30
+ ),
31
+ };
32
+ }
33
+
34
+ export function addTimeSlot(day: DaySchedule): DaySchedule {
35
+ return {
36
+ ...day,
37
+ slots: [...getEditableTimeSlots(day), { ...DEFAULT_TIME_SLOT }],
38
+ };
39
+ }
40
+
41
+ export function removeTimeSlot(
42
+ day: DaySchedule,
43
+ slotIndex: number,
44
+ ): DaySchedule {
45
+ const slots = getEditableTimeSlots(day).filter(
46
+ (_, index) => index !== slotIndex,
47
+ );
48
+
49
+ return {
50
+ ...day,
51
+ slots: slots.length > 0 ? slots : [{ ...DEFAULT_TIME_SLOT }],
52
+ };
53
+ }
@@ -230,6 +230,11 @@ export function getLocalTimezone() {
230
230
  return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
231
231
  }
232
232
 
233
+ /** New event drafts follow the viewer's browser zone unless they name one. */
234
+ export function resolveEventTimezone(timezone?: string | null) {
235
+ return timezone?.trim() || getLocalTimezone();
236
+ }
237
+
233
238
  function getTimezoneOffsetMs(date: Date, timezone: string) {
234
239
  const parts = new Intl.DateTimeFormat("en-US", {
235
240
  timeZone: timezone,
@@ -1,5 +1,6 @@
1
1
  import { useT } from "@agent-native/core/client/i18n";
2
2
  import type { AvailabilityConfig, DaySchedule } from "@shared/api";
3
+ import { IconPlus, IconTrash } from "@tabler/icons-react";
3
4
  import { useState, useEffect } from "react";
4
5
  import { toast } from "sonner";
5
6
 
@@ -21,6 +22,14 @@ import {
21
22
  useUpdateAvailability,
22
23
  } from "@/hooks/use-availability";
23
24
  import { useDbStatus } from "@/hooks/use-db-status";
25
+ import {
26
+ DEFAULT_TIME_SLOT,
27
+ addTimeSlot,
28
+ getEditableTimeSlots,
29
+ removeTimeSlot,
30
+ setDayEnabled,
31
+ updateTimeSlot,
32
+ } from "@/lib/availability-schedule";
24
33
  import { copyTextToClipboard } from "@/lib/clipboard";
25
34
 
26
35
  type DayName = keyof AvailabilityConfig["weeklySchedule"];
@@ -37,7 +46,7 @@ const DAYS: { key: DayName }[] = [
37
46
 
38
47
  const DEFAULT_SCHEDULE: DaySchedule = {
39
48
  enabled: false,
40
- slots: [{ start: "09:00", end: "17:00" }],
49
+ slots: [{ ...DEFAULT_TIME_SLOT }],
41
50
  };
42
51
 
43
52
  export default function AvailabilitySettings() {
@@ -93,17 +102,36 @@ export default function AvailabilitySettings() {
93
102
  function updateDay(day: DayName, updates: Partial<DaySchedule>) {
94
103
  setSchedule((prev) => ({
95
104
  ...prev,
96
- [day]: { ...prev[day], ...updates },
105
+ [day]:
106
+ typeof updates.enabled === "boolean"
107
+ ? setDayEnabled(prev[day], updates.enabled)
108
+ : { ...prev[day], ...updates },
97
109
  }));
98
110
  }
99
111
 
100
- function updateDaySlot(day: DayName, field: "start" | "end", value: string) {
112
+ function updateDaySlot(
113
+ day: DayName,
114
+ slotIndex: number,
115
+ field: "start" | "end",
116
+ value: string,
117
+ ) {
101
118
  setSchedule((prev) => ({
102
119
  ...prev,
103
- [day]: {
104
- ...prev[day],
105
- slots: [{ ...prev[day].slots[0], [field]: value }],
106
- },
120
+ [day]: updateTimeSlot(prev[day], slotIndex, field, value),
121
+ }));
122
+ }
123
+
124
+ function addDaySlot(day: DayName) {
125
+ setSchedule((prev) => ({
126
+ ...prev,
127
+ [day]: addTimeSlot(prev[day]),
128
+ }));
129
+ }
130
+
131
+ function removeDaySlot(day: DayName, slotIndex: number) {
132
+ setSchedule((prev) => ({
133
+ ...prev,
134
+ [day]: removeTimeSlot(prev[day], slotIndex),
107
135
  }));
108
136
  }
109
137
 
@@ -181,7 +209,7 @@ export default function AvailabilitySettings() {
181
209
  </div>
182
210
  {DAYS.map(({ key }) => {
183
211
  const day = schedule[key];
184
- const slot = day.slots[0] ?? { start: "09:00", end: "17:00" };
212
+ const slots = getEditableTimeSlots(day);
185
213
  return (
186
214
  <div
187
215
  key={key}
@@ -198,26 +226,60 @@ export default function AvailabilitySettings() {
198
226
  </div>
199
227
 
200
228
  {day.enabled ? (
201
- <div className="flex items-center gap-2">
202
- <Input
203
- type="time"
204
- value={slot.start}
205
- onChange={(e) =>
206
- updateDaySlot(key, "start", e.target.value)
207
- }
208
- className="w-28 sm:w-32"
209
- />
210
- <span className="text-muted-foreground">
211
- {t("bookingLinks.to")}
212
- </span>
213
- <Input
214
- type="time"
215
- value={slot.end}
216
- onChange={(e) =>
217
- updateDaySlot(key, "end", e.target.value)
218
- }
219
- className="w-28 sm:w-32"
220
- />
229
+ <div className="min-w-0 flex-1 space-y-2">
230
+ {slots.map((slot, slotIndex) => (
231
+ <div
232
+ key={`${key}-${slotIndex}`}
233
+ className="flex flex-wrap items-center gap-2"
234
+ >
235
+ <Input
236
+ type="time"
237
+ value={slot.start}
238
+ onChange={(e) =>
239
+ updateDaySlot(
240
+ key,
241
+ slotIndex,
242
+ "start",
243
+ e.target.value,
244
+ )
245
+ }
246
+ className="w-28 sm:w-32"
247
+ />
248
+ <span className="text-muted-foreground">
249
+ {t("bookingLinks.to")}
250
+ </span>
251
+ <Input
252
+ type="time"
253
+ value={slot.end}
254
+ onChange={(e) =>
255
+ updateDaySlot(key, slotIndex, "end", e.target.value)
256
+ }
257
+ className="w-28 sm:w-32"
258
+ />
259
+ {slots.length > 1 && (
260
+ <Button
261
+ type="button"
262
+ variant="ghost"
263
+ size="sm"
264
+ className="h-8 px-2 text-muted-foreground hover:text-destructive"
265
+ onClick={() => removeDaySlot(key, slotIndex)}
266
+ >
267
+ <IconTrash className="mr-1.5 h-3.5 w-3.5" />
268
+ {t("eventForm.delete")}
269
+ </Button>
270
+ )}
271
+ </div>
272
+ ))}
273
+ <Button
274
+ type="button"
275
+ variant="ghost"
276
+ size="sm"
277
+ className="h-8 px-2"
278
+ onClick={() => addDaySlot(key)}
279
+ >
280
+ <IconPlus className="mr-1.5 h-3.5 w-3.5" />
281
+ {t("bookingLinks.add")}
282
+ </Button>
221
283
  </div>
222
284
  ) : (
223
285
  <span className="text-sm text-muted-foreground">