@fayz-ai/plugin-agenda 0.8.4 → 0.9.0-next.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAiBnD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,cAAc,CA8NhF;AAGD,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAGtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACtD,YAAY,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC5E,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAClI,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAA;AAGlG,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,uBAAuB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAiBnD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,cAAc,CAsQhF;AAGD,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAGtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACtD,YAAY,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC5E,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAClI,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAA;AAGlG,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,uBAAuB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createMockAgendaProvider, createSupabasePublicBookingProvider } from './chunk-Q2PAWBPR.js';
2
2
  export { createMockAgendaProvider } from './chunk-Q2PAWBPR.js';
3
3
  import React13, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
4
- import { getSupabaseClientOptional, getActiveTenantId, registerTranslations, createSafeDataProvider, usePluginRuntimeOptional, useTranslation, getCurrentLocale, useDataChanged, formatCurrency } from '@fayz-ai/core';
4
+ import { getSupabaseClientOptional, getActiveTenantId, registerTranslations, createSafeDataProvider, emitDataChanged, usePluginRuntimeOptional, useTranslation, getCurrentLocale, useDataChanged, formatCurrency } from '@fayz-ai/core';
5
5
  import { createPluginContext, setScheduleBlockConfig, getScheduleBlockConfig, PluginSettingsPanel, dedup, useTenantPluginSettings, SettingsGroup, ToggleRow, SelectRow, usePluginPrefs, PersonLink, useLimitGuard, CrudFormPage, CrudDetailPage, ContactPicker, invalidateLimit } from '@fayz-ai/saas';
6
6
  import FullCalendar from '@fullcalendar/react';
7
7
  import dayGridPlugin from '@fullcalendar/daygrid';
@@ -2712,6 +2712,27 @@ function CalendarView() {
2712
2712
  setFilters({ statuses: next });
2713
2713
  }
2714
2714
  const wrapperRef = useRef(null);
2715
+ useEffect(() => {
2716
+ const container = wrapperRef.current;
2717
+ if (!container) return;
2718
+ let frame = 0;
2719
+ let lastWidth = container.clientWidth;
2720
+ let lastHeight = container.clientHeight;
2721
+ const ro = new ResizeObserver(() => {
2722
+ const width = container.clientWidth;
2723
+ const height = container.clientHeight;
2724
+ if (width === lastWidth && height === lastHeight) return;
2725
+ lastWidth = width;
2726
+ lastHeight = height;
2727
+ cancelAnimationFrame(frame);
2728
+ frame = requestAnimationFrame(() => calendarRef.current?.getApi()?.updateSize());
2729
+ });
2730
+ ro.observe(container);
2731
+ return () => {
2732
+ cancelAnimationFrame(frame);
2733
+ ro.disconnect();
2734
+ };
2735
+ }, [isMobile, mobileGridActive, professionalsLoading, professionals.length]);
2715
2736
  const [dayHeaderCompact, setDayHeaderCompact] = useState(false);
2716
2737
  useEffect(() => {
2717
2738
  const container = wrapperRef.current;
@@ -3689,6 +3710,7 @@ function createAgendaStore(provider2, financialBridge) {
3689
3710
  const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
3690
3711
  set({ bookings });
3691
3712
  }
3713
+ emitDataChanged({ table: "appointments", op: "create", id: booking.id, source: "ui" });
3692
3714
  toast.success("Appointment created");
3693
3715
  return booking;
3694
3716
  } catch (err) {
@@ -3704,6 +3726,7 @@ function createAgendaStore(provider2, financialBridge) {
3704
3726
  const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
3705
3727
  set({ bookings });
3706
3728
  }
3729
+ emitDataChanged({ table: "appointments", op: "update", id, source: "ui" });
3707
3730
  toast.success("Appointment updated");
3708
3731
  return booking;
3709
3732
  } catch (err) {
@@ -3719,6 +3742,7 @@ function createAgendaStore(provider2, financialBridge) {
3719
3742
  const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
3720
3743
  set({ bookings });
3721
3744
  }
3745
+ emitDataChanged({ table: "appointments", op: "delete", id, source: "ui" });
3722
3746
  toast.success("Appointment deleted");
3723
3747
  } catch (err) {
3724
3748
  toast.error("Failed to delete appointment", { description: err?.message });
@@ -3735,6 +3759,7 @@ function createAgendaStore(provider2, financialBridge) {
3735
3759
  const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
3736
3760
  set({ bookings });
3737
3761
  }
3762
+ emitDataChanged({ table: "appointments", op: "update", id, source: "ui" });
3738
3763
  toast.success("Status updated");
3739
3764
  } catch (err) {
3740
3765
  set({ bookings: prev });
@@ -5577,6 +5602,14 @@ var googleCalendarConnectorDef = {
5577
5602
  description: "Two-way sync between your bookings and Google Calendar.",
5578
5603
  icon: "Calendar",
5579
5604
  authKind: "oauth",
5605
+ category: "scheduling",
5606
+ direction: "outbound",
5607
+ // Sync only, and deliberately: the agenda has to exist inside the app — to be
5608
+ // listed, filtered, reported on, and read when Google is unreachable. An
5609
+ // agentic plane would answer questions but leave the calendar screen empty.
5610
+ planes: ["sync"],
5611
+ entities: ["booking"],
5612
+ docsUrl: "https://support.google.com/calendar",
5580
5613
  async getStatus() {
5581
5614
  const integ = await provider.getIntegration();
5582
5615
  return { connected: !!integ?.connected };
@@ -5699,6 +5732,12 @@ function createAgendaPlugin(options) {
5699
5732
  kind: "write",
5700
5733
  description: "Guarded appointment create: agent_guard (role\u2192plan\u2192bookings_month cap), working hours, race-safe conflict check, audited.",
5701
5734
  audits: true
5735
+ },
5736
+ {
5737
+ name: "agent_agenda_update_appointment",
5738
+ kind: "write",
5739
+ description: "Guarded appointment reschedule/reassign/cancel: agent_guard (role\u2192plan, no cap), working hours, race-safe conflict check that skips the appointment itself, audited.",
5740
+ audits: true
5702
5741
  }
5703
5742
  ],
5704
5743
  navigation: [
@@ -5768,6 +5807,35 @@ function createAgendaPlugin(options) {
5768
5807
  ],
5769
5808
  permission: { feature: "appointments", action: "create" }
5770
5809
  },
5810
+ {
5811
+ id: "agenda.update-appointment",
5812
+ name: "updateAppointment",
5813
+ description: "Changes an appointment that ALREADY EXISTS: reschedule (starts_at), reassign (professional_id), cancel or confirm (status), or annotate (notes). This is the ONLY way to change an appointment \u2014 the appointments entity is a read-only view, so updateRecord cannot touch it. NEVER answer a reschedule or a cancellation by creating a new appointment: that leaves the original standing and double-books the professional. Takes the appointment id from a previous search. The duration is preserved automatically. The user confirms before anything changes.",
5814
+ icon: "CalendarClock",
5815
+ mode: "persist",
5816
+ execution: { plane: "server", kind: "rpc", rpc: "agent_agenda_update_appointment" },
5817
+ category: "Scheduling",
5818
+ parameters: {
5819
+ type: "object",
5820
+ properties: {
5821
+ appointment_id: { type: "string", description: "Id of the appointment to change (from a search)" },
5822
+ starts_at: { type: "string", description: "New LOCAL date-time of the business, NO timezone suffix \u2014 e.g. '2026-07-27T16:30'. Omit to keep the current time." },
5823
+ professional_id: { type: "string", description: "Move to another professional (optional)" },
5824
+ status: {
5825
+ type: "string",
5826
+ description: 'New status \u2014 use "cancelled" to cancel',
5827
+ enum: ["scheduled", "confirmed", "in_progress", "completed", "cancelled", "no_show"]
5828
+ },
5829
+ notes: { type: "string", description: "Optional notes" }
5830
+ },
5831
+ required: ["appointment_id"]
5832
+ },
5833
+ suggestions: [
5834
+ { label: "Remarca o Gustavo para 16:30" },
5835
+ { label: "Cancela o atendimento das 10h" }
5836
+ ],
5837
+ permission: { feature: "appointments", action: "edit" }
5838
+ },
5771
5839
  {
5772
5840
  id: "agenda.check-availability",
5773
5841
  name: "checkAvailability",