@elizaos/ui 2.0.0-alpha.385 → 2.0.0-alpha.392
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/app-companion/src/components/companion/CompanionAppView.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/CompanionAppView.js +6 -4
- package/apps/app-companion/src/components/companion/CompanionView.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/CompanionView.js +6 -4
- package/apps/app-lifeops/src/api/client-lifeops.js +6 -0
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.d.ts +3 -0
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.js +189 -0
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.d.ts +2 -0
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.js +1065 -0
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.d.ts +7 -0
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.js +71 -0
- package/apps/app-lifeops/src/components/DataSourcesStrip.d.ts +14 -0
- package/apps/app-lifeops/src/components/DataSourcesStrip.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/DataSourcesStrip.js +36 -0
- package/apps/app-lifeops/src/components/EventEditorDrawer.d.ts +23 -0
- package/apps/app-lifeops/src/components/EventEditorDrawer.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/EventEditorDrawer.js +514 -0
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.js +10 -0
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.d.ts +15 -0
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.js +515 -0
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.d.ts +34 -0
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.js +175 -0
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.js +99 -0
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.d.ts +37 -0
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.js +88 -0
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.d.ts +13 -0
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.js +490 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.d.ts +12 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.js +92 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.d.ts +12 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.js +160 -0
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.d.ts +3 -0
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.js +373 -0
- package/apps/app-lifeops/src/components/LifeOpsNavRail.d.ts +9 -0
- package/apps/app-lifeops/src/components/LifeOpsNavRail.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsNavRail.js +93 -0
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.d.ts +4 -0
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.js +274 -0
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.d.ts +7 -0
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.js +657 -0
- package/apps/app-lifeops/src/components/LifeOpsPageSections.d.ts +42 -0
- package/apps/app-lifeops/src/components/LifeOpsPageSections.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsPageSections.js +166 -0
- package/apps/app-lifeops/src/components/LifeOpsPageView.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsPageView.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsPageView.js +566 -0
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.js +749 -0
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.d.ts +27 -0
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.js +106 -0
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.js +373 -0
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.d.ts +10 -0
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.js +30 -0
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.d.ts +21 -0
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.js +30 -0
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.d.ts +20 -0
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.js +597 -0
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.d.ts +13 -0
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.js +134 -0
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.d.ts +10 -0
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.js +425 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.d.ts +11 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.js +49 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.js +1041 -0
- package/apps/app-lifeops/src/components/MessagingConnectorCards.d.ts +7 -0
- package/apps/app-lifeops/src/components/MessagingConnectorCards.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/MessagingConnectorCards.js +643 -0
- package/apps/app-lifeops/src/components/MissingSourceCard.d.ts +9 -0
- package/apps/app-lifeops/src/components/MissingSourceCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/MissingSourceCard.js +5 -0
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.d.ts +2 -0
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.js +163 -0
- package/apps/app-lifeops/src/components/SleepInspectionPanel.d.ts +8 -0
- package/apps/app-lifeops/src/components/SleepInspectionPanel.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/SleepInspectionPanel.js +59 -0
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.d.ts +3 -0
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.js +75 -0
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.d.ts +8 -0
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.js +48 -0
- package/apps/app-lifeops/src/components/lifeops-labels.d.ts +2 -0
- package/apps/app-lifeops/src/components/lifeops-labels.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/lifeops-labels.js +5 -0
- package/apps/app-lifeops/src/events/index.d.ts +34 -0
- package/apps/app-lifeops/src/events/index.d.ts.map +1 -0
- package/apps/app-lifeops/src/events/index.js +23 -0
- package/apps/app-lifeops/src/hooks/useCalendarWeek.d.ts +28 -0
- package/apps/app-lifeops/src/hooks/useCalendarWeek.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useCalendarWeek.js +93 -0
- package/apps/app-lifeops/src/hooks/useDiscordConnector.d.ts +14 -0
- package/apps/app-lifeops/src/hooks/useDiscordConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useDiscordConnector.js +126 -0
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.d.ts +29 -0
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.js +481 -0
- package/apps/app-lifeops/src/hooks/useIMessageConnector.d.ts +10 -0
- package/apps/app-lifeops/src/hooks/useIMessageConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useIMessageConnector.js +50 -0
- package/apps/app-lifeops/src/hooks/useInbox.d.ts +34 -0
- package/apps/app-lifeops/src/hooks/useInbox.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useInbox.js +98 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.d.ts +2 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.js +383 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.d.ts +9 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.js +83 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.d.ts +8 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.js +60 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.d.ts +18 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.js +66 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.d.ts +14 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.js +79 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.d.ts +18 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.js +78 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.d.ts +14 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.js +160 -0
- package/apps/app-lifeops/src/hooks/useSignalConnector.d.ts +16 -0
- package/apps/app-lifeops/src/hooks/useSignalConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useSignalConnector.js +198 -0
- package/apps/app-lifeops/src/hooks/useTelegramConnector.d.ts +21 -0
- package/apps/app-lifeops/src/hooks/useTelegramConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useTelegramConnector.js +177 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.d.ts +8 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.js +58 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.d.ts +12 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.js +152 -0
- package/apps/app-lifeops/src/lifeops/discord-browser-scraper.js +1 -1
- package/apps/app-lifeops/src/lifeops/google-gmail.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-gmail.js +74 -26
- package/apps/app-lifeops/src/lifeops/google-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-managed-client.js +4 -5
- package/apps/app-lifeops/src/lifeops/google-oauth.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-oauth.js +2 -2
- package/apps/app-lifeops/src/lifeops/owner-profile.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/owner-profile.js +1 -1
- package/apps/app-lifeops/src/lifeops/paypal-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/paypal-managed-client.js +4 -5
- package/apps/app-lifeops/src/lifeops/plaid-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/plaid-managed-client.js +4 -5
- package/apps/app-lifeops/src/lifeops/schedule-sync-client.js +2 -2
- package/apps/app-lifeops/src/lifeops/service-constants.d.ts +1 -0
- package/apps/app-lifeops/src/lifeops/service-constants.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-constants.js +1 -0
- package/apps/app-lifeops/src/lifeops/service-mixin-core.d.ts +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-core.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-core.js +2 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-imessage.js +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.d.ts +3 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.js +42 -13
- package/apps/app-lifeops/src/lifeops/service-mixin-reminders.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-reminders.js +3 -2
- package/apps/app-lifeops/src/lifeops/service-mixin-workflows.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-workflows.js +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-calendar.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-calendar.js +3 -3
- package/apps/app-lifeops/src/lifeops/service-normalize-connector.d.ts +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-connector.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-connector.js +2 -2
- package/apps/app-lifeops/src/lifeops/signal-auth.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/signal-auth.js +6 -3
- package/apps/app-lifeops/src/lifeops/telegram-auth.js +1 -1
- package/apps/app-lifeops/src/lifeops/travel-adapters/duffel.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/travel-adapters/duffel.js +31 -6
- package/apps/app-lifeops/src/lifeops/twilio.js +1 -1
- package/apps/app-lifeops/src/lifeops/x-poster.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/x-poster.js +13 -3
- package/apps/app-lifeops/src/lifeops-route.d.ts +74 -0
- package/apps/app-lifeops/src/lifeops-route.d.ts.map +1 -0
- package/apps/app-lifeops/src/lifeops-route.js +204 -0
- package/apps/app-lifeops/src/platform/lifeops-github.d.ts +15 -0
- package/apps/app-lifeops/src/platform/lifeops-github.d.ts.map +1 -0
- package/apps/app-lifeops/src/platform/lifeops-github.js +135 -0
- package/apps/app-lifeops/src/routes/cloud-features-routes.d.ts +2 -2
- package/apps/app-lifeops/src/routes/cloud-features-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/cloud-features-routes.js +5 -3
- package/apps/app-lifeops/src/routes/lifeops-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/lifeops-routes.js +15 -3
- package/apps/app-lifeops/src/routes/plugin.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/plugin.js +10 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.d.ts +1 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.js +4 -2
- package/apps/app-lifeops/src/routes/website-blocker-routes.d.ts +1 -1
- package/apps/app-lifeops/src/routes/website-blocker-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/ui.d.ts +11 -0
- package/apps/app-lifeops/src/ui.d.ts.map +1 -0
- package/apps/app-lifeops/src/ui.js +9 -0
- package/apps/app-lifeops/src/utils/lifeops-url.d.ts +5 -0
- package/apps/app-lifeops/src/utils/lifeops-url.d.ts.map +1 -0
- package/apps/app-lifeops/src/utils/lifeops-url.js +35 -0
- package/apps/app-lifeops/src/website-blocker/access.d.ts.map +1 -1
- package/apps/app-lifeops/src/website-blocker/access.js +1 -1
- package/apps/app-steward/src/routes/steward-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/steward-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/steward-compat-routes.js +3 -1
- package/apps/app-steward/src/routes/wallet-browser-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/wallet-browser-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-browser-compat-routes.js +3 -1
- package/apps/app-steward/src/routes/wallet-bsc-core-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-bsc-core-routes.js +2 -1
- package/apps/app-steward/src/routes/wallet-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/wallet-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-compat-routes.js +3 -1
- package/apps/app-steward/src/routes/wallet-core-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-core-routes.js +2 -1
- package/apps/app-steward/src/routes/wallet-trade-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/wallet-trade-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-trade-compat-routes.js +3 -1
- package/apps/app-training/src/core/dataset-generator.d.ts +1 -1
- package/apps/app-training/src/core/dataset-generator.d.ts.map +1 -1
- package/apps/app-training/src/core/roleplay-executor.d.ts +1 -1
- package/apps/app-training/src/core/roleplay-executor.d.ts.map +1 -1
- package/apps/app-training/src/core/trajectory-task-datasets.d.ts +1 -1
- package/apps/app-training/src/core/trajectory-task-datasets.d.ts.map +1 -1
- package/apps/app-training/src/index.d.ts +1 -2
- package/apps/app-training/src/index.d.ts.map +1 -1
- package/apps/app-training/src/index.js +1 -2
- package/apps/app-training/src/routes/training-routes.d.ts +1 -1
- package/apps/app-training/src/routes/training-routes.d.ts.map +1 -1
- package/apps/app-training/src/routes/training-routes.js +1 -1
- package/apps/app-training/src/routes/trajectory-routes.d.ts +1 -1
- package/apps/app-training/src/routes/trajectory-routes.d.ts.map +1 -1
- package/apps/app-training/src/routes/trajectory-routes.js +3 -1
- package/apps/app-training/src/services/training-service-like.d.ts +1 -1
- package/apps/app-training/src/services/training-service-like.d.ts.map +1 -1
- package/apps/app-training/src/services/training-service.d.ts +1 -1
- package/apps/app-training/src/services/training-service.d.ts.map +1 -1
- package/package.json +1 -1
- package/packages/agent/src/api/provider-switch-config.js +1 -1
- package/packages/agent/src/api/server-helpers-auth.d.ts.map +1 -1
- package/packages/agent/src/api/server-helpers-auth.js +5 -4
- package/packages/agent/src/providers/media-provider.d.ts +1 -1
- package/packages/agent/src/providers/media-provider.d.ts.map +1 -1
- package/packages/app-core/src/App.d.ts.map +1 -1
- package/packages/app-core/src/App.js +20 -12
- package/packages/app-core/src/api/auth.d.ts.map +1 -1
- package/packages/app-core/src/api/auth.js +5 -5
- package/packages/app-core/src/api/client-types-experience.d.ts +7 -0
- package/packages/app-core/src/api/client-types-experience.d.ts.map +1 -1
- package/packages/app-core/src/components/apps/helpers.d.ts +1 -1
- package/packages/app-core/src/components/apps/helpers.d.ts.map +1 -1
- package/packages/app-core/src/components/apps/helpers.js +1 -0
- package/packages/app-core/src/components/apps/internal-tool-apps.d.ts +11 -0
- package/packages/app-core/src/components/apps/internal-tool-apps.d.ts.map +1 -1
- package/packages/app-core/src/components/apps/internal-tool-apps.js +31 -0
- package/packages/app-core/src/components/apps/launch-history.d.ts +16 -0
- package/packages/app-core/src/components/apps/launch-history.d.ts.map +1 -0
- package/packages/app-core/src/components/apps/launch-history.js +77 -0
- package/packages/app-core/src/components/apps/per-app-config.d.ts +19 -0
- package/packages/app-core/src/components/apps/per-app-config.d.ts.map +1 -0
- package/packages/app-core/src/components/apps/per-app-config.js +99 -0
- package/packages/app-core/src/components/apps/useRegistryCatalog.d.ts +14 -0
- package/packages/app-core/src/components/apps/useRegistryCatalog.d.ts.map +1 -0
- package/packages/app-core/src/components/apps/useRegistryCatalog.js +52 -0
- package/packages/app-core/src/components/auth/LoginView.d.ts +1 -19
- package/packages/app-core/src/components/auth/LoginView.d.ts.map +1 -1
- package/packages/app-core/src/components/auth/LoginView.js +4 -99
- package/packages/app-core/src/components/character/CharacterExperienceWorkspace.d.ts.map +1 -1
- package/packages/app-core/src/components/character/CharacterExperienceWorkspace.js +14 -2
- package/packages/app-core/src/components/character/character-hub-helpers.d.ts.map +1 -1
- package/packages/app-core/src/components/character/character-hub-helpers.js +7 -0
- package/packages/app-core/src/components/character/character-hub-types.d.ts +7 -0
- package/packages/app-core/src/components/character/character-hub-types.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/BootstrapStep.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/BootstrapStep.js +3 -2
- package/packages/app-core/src/components/pages/AppDetailsView.d.ts +36 -0
- package/packages/app-core/src/components/pages/AppDetailsView.d.ts.map +1 -0
- package/packages/app-core/src/components/pages/AppDetailsView.js +289 -0
- package/packages/app-core/src/components/pages/AppsView.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/AppsView.js +134 -42
- package/packages/app-core/src/components/shell/StartupShell.d.ts.map +1 -1
- package/packages/app-core/src/components/shell/StartupShell.js +2 -5
- package/packages/app-core/src/i18n/locales/en.json +256 -205
- package/packages/app-core/src/i18n/locales/es.json +256 -205
- package/packages/app-core/src/i18n/locales/ko.json +256 -205
- package/packages/app-core/src/i18n/locales/pt.json +256 -205
- package/packages/app-core/src/i18n/locales/tl.json +256 -205
- package/packages/app-core/src/i18n/locales/vi.json +256 -205
- package/packages/app-core/src/i18n/locales/zh-CN.json +256 -205
- package/packages/app-core/src/navigation/index.d.ts.map +1 -1
- package/packages/app-core/src/navigation/index.js +6 -0
- package/packages/app-core/src/shell/AppWindowRenderer.d.ts +17 -0
- package/packages/app-core/src/shell/AppWindowRenderer.d.ts.map +1 -0
- package/packages/app-core/src/shell/AppWindowRenderer.js +337 -0
- package/packages/app-core/src/shell/DetachedShellRoot.js +4 -1
- package/packages/app-core/src/shell/index.d.ts +1 -0
- package/packages/app-core/src/shell/index.d.ts.map +1 -1
- package/packages/app-core/src/shell/index.js +1 -0
- package/packages/app-core/src/state/startup-coordinator.d.ts.map +1 -1
- package/packages/app-core/src/state/startup-coordinator.js +0 -3
- package/packages/app-core/src/state/startup-phase-poll.d.ts.map +1 -1
- package/packages/app-core/src/state/startup-phase-poll.js +2 -4
- package/packages/app-core/src/state/usePluginsSkillsState.d.ts +6 -6
- package/packages/native-plugins/mobile-signals/src/definitions.d.ts +162 -0
- package/packages/native-plugins/mobile-signals/src/definitions.d.ts.map +1 -0
- package/packages/native-plugins/mobile-signals/src/definitions.js +1 -0
- package/packages/native-plugins/mobile-signals/src/index.d.ts +4 -0
- package/packages/native-plugins/mobile-signals/src/index.d.ts.map +1 -0
- package/packages/native-plugins/mobile-signals/src/index.js +6 -0
- package/packages/native-plugins/mobile-signals/src/web.d.ts +29 -0
- package/packages/native-plugins/mobile-signals/src/web.d.ts.map +1 -0
- package/packages/native-plugins/mobile-signals/src/web.js +269 -0
- package/packages/shared/src/app-hero-art.d.ts.map +1 -1
- package/packages/shared/src/app-hero-art.js +13 -0
- package/packages/shared/src/contracts/lifeops.d.ts +10 -0
- package/packages/shared/src/contracts/lifeops.d.ts.map +1 -1
- package/packages/shared/src/contracts/lifeops.js +5 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/actions/record-experience.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/actions/record-experience.js +46 -4
- package/packages/typescript/src/features/advanced-capabilities/experience/evaluators/experienceEvaluator.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/evaluators/experienceEvaluator.js +34 -124
- package/packages/typescript/src/features/advanced-capabilities/experience/service.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/service.js +56 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/types.d.ts +7 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/types.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/utils/experienceText.d.ts +7 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/utils/experienceText.d.ts.map +1 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/utils/experienceText.js +123 -0
- package/apps/app-training/src/ui/FineTuningView.d.ts +0 -5
- package/apps/app-training/src/ui/FineTuningView.d.ts.map +0 -1
- package/apps/app-training/src/ui/FineTuningView.js +0 -388
- package/apps/app-training/src/ui/fine-tuning-panels.d.ts +0 -111
- package/apps/app-training/src/ui/fine-tuning-panels.d.ts.map +0 -1
- package/apps/app-training/src/ui/fine-tuning-panels.js +0 -130
- package/apps/app-training/src/ui/index.d.ts +0 -3
- package/apps/app-training/src/ui/index.d.ts.map +0 -1
- package/apps/app-training/src/ui/index.js +0 -2
- package/packages/app-core/src/api/trusted-local-request.d.ts +0 -4
- package/packages/app-core/src/api/trusted-local-request.d.ts.map +0 -1
- package/packages/app-core/src/api/trusted-local-request.js +0 -176
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Button, client, Input, openExternalUrl, Spinner, useMediaQuery, useApp, } from "@elizaos/app-core";
|
|
3
|
+
import { LIFEOPS_INBOX_CHANNELS, } from "@elizaos/shared";
|
|
4
|
+
import { AlarmClock, ArrowLeft, AtSign, CalendarClock, ExternalLink, MessageCircle, MessageSquare, MessageSquareReply, Phone, Search, Send, Shield, Smartphone, Sparkles, } from "lucide-react";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useState, } from "react";
|
|
6
|
+
import { useInbox, } from "../hooks/useInbox.js";
|
|
7
|
+
import { buildMessageChatPrefill, buildReplyPrefill, useLifeOpsChatLauncher, } from "./LifeOpsChatAdapter.js";
|
|
8
|
+
import { useLifeOpsSelection, } from "./LifeOpsSelectionContext.js";
|
|
9
|
+
const CHANNEL_STYLES = {
|
|
10
|
+
gmail: {
|
|
11
|
+
label: "Gmail",
|
|
12
|
+
bg: "bg-rose-500/16",
|
|
13
|
+
ring: "ring-rose-500/40",
|
|
14
|
+
text: "text-rose-300",
|
|
15
|
+
icon: _jsx(AtSign, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
16
|
+
},
|
|
17
|
+
x_dm: {
|
|
18
|
+
label: "X DMs",
|
|
19
|
+
bg: "bg-zinc-500/18",
|
|
20
|
+
ring: "ring-zinc-400/40",
|
|
21
|
+
text: "text-zinc-200",
|
|
22
|
+
icon: _jsx(MessageSquareReply, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
23
|
+
},
|
|
24
|
+
discord: {
|
|
25
|
+
label: "Discord",
|
|
26
|
+
bg: "bg-indigo-500/18",
|
|
27
|
+
ring: "ring-indigo-500/40",
|
|
28
|
+
text: "text-indigo-300",
|
|
29
|
+
icon: _jsx(MessageCircle, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
30
|
+
},
|
|
31
|
+
telegram: {
|
|
32
|
+
label: "Telegram",
|
|
33
|
+
bg: "bg-sky-500/18",
|
|
34
|
+
ring: "ring-sky-500/40",
|
|
35
|
+
text: "text-sky-300",
|
|
36
|
+
icon: _jsx(Send, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
37
|
+
},
|
|
38
|
+
signal: {
|
|
39
|
+
label: "Signal",
|
|
40
|
+
bg: "bg-blue-500/18",
|
|
41
|
+
ring: "ring-blue-500/40",
|
|
42
|
+
text: "text-blue-300",
|
|
43
|
+
icon: _jsx(Shield, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
44
|
+
},
|
|
45
|
+
imessage: {
|
|
46
|
+
label: "iMessage",
|
|
47
|
+
bg: "bg-emerald-500/18",
|
|
48
|
+
ring: "ring-emerald-500/40",
|
|
49
|
+
text: "text-emerald-300",
|
|
50
|
+
icon: _jsx(MessageSquare, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
51
|
+
},
|
|
52
|
+
whatsapp: {
|
|
53
|
+
label: "WhatsApp",
|
|
54
|
+
bg: "bg-lime-500/18",
|
|
55
|
+
ring: "ring-lime-500/40",
|
|
56
|
+
text: "text-lime-300",
|
|
57
|
+
icon: _jsx(Smartphone, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
58
|
+
},
|
|
59
|
+
sms: {
|
|
60
|
+
label: "SMS",
|
|
61
|
+
bg: "bg-amber-500/18",
|
|
62
|
+
ring: "ring-amber-500/40",
|
|
63
|
+
text: "text-amber-300",
|
|
64
|
+
icon: _jsx(Phone, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const ALL_CHANNEL_STYLE = {
|
|
68
|
+
label: "All",
|
|
69
|
+
bg: "bg-violet-500/16",
|
|
70
|
+
ring: "ring-violet-500/40",
|
|
71
|
+
text: "text-violet-300",
|
|
72
|
+
icon: _jsx(MessageSquare, { className: "h-3.5 w-3.5", "aria-hidden": true }),
|
|
73
|
+
};
|
|
74
|
+
export const LIFEOPS_MESSAGE_CHANNELS = LIFEOPS_INBOX_CHANNELS.filter((channel) => channel !== "gmail");
|
|
75
|
+
export const LIFEOPS_MAIL_CHANNELS = ["gmail"];
|
|
76
|
+
const SMALL_GROUP_PARTICIPANT_CAP = 15;
|
|
77
|
+
const IMPORTANT_PRIORITY_SCORE_THRESHOLD = 70;
|
|
78
|
+
const MISSED_REPLY_GAP_MS = 24 * 60 * 60 * 1000;
|
|
79
|
+
const MISSED_MIN_PRIORITY = 50;
|
|
80
|
+
const ALL_GMAIL_ACCOUNTS = "__all__";
|
|
81
|
+
function styleFor(channel) {
|
|
82
|
+
return CHANNEL_STYLES[channel];
|
|
83
|
+
}
|
|
84
|
+
function styleForFilter(channel) {
|
|
85
|
+
return channel === "all"
|
|
86
|
+
? ALL_CHANNEL_STYLE
|
|
87
|
+
: CHANNEL_STYLES[channel];
|
|
88
|
+
}
|
|
89
|
+
function messagesForThreadGroup(group) {
|
|
90
|
+
const messages = Array.isArray(group.messages) ? group.messages : [];
|
|
91
|
+
return messages.length > 0 ? messages : [group.latestMessage];
|
|
92
|
+
}
|
|
93
|
+
function computeMissedAgeMs(message) {
|
|
94
|
+
if (typeof message.repliedAt === "string" && message.repliedAt.length > 0) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const received = Date.parse(message.receivedAt);
|
|
98
|
+
if (!Number.isFinite(received))
|
|
99
|
+
return null;
|
|
100
|
+
const age = Date.now() - received;
|
|
101
|
+
return age >= MISSED_REPLY_GAP_MS ? age : null;
|
|
102
|
+
}
|
|
103
|
+
function formatMissedAge(ageMs) {
|
|
104
|
+
const days = Math.floor(ageMs / (24 * 60 * 60 * 1000));
|
|
105
|
+
if (days >= 1)
|
|
106
|
+
return `${days}d ago`;
|
|
107
|
+
const hours = Math.max(1, Math.floor(ageMs / (60 * 60 * 1000)));
|
|
108
|
+
return `${hours}h ago`;
|
|
109
|
+
}
|
|
110
|
+
function formatRelativeTime(receivedAt) {
|
|
111
|
+
const parsed = Date.parse(receivedAt);
|
|
112
|
+
if (!Number.isFinite(parsed))
|
|
113
|
+
return "";
|
|
114
|
+
const diffMs = Date.now() - parsed;
|
|
115
|
+
const diffMin = Math.floor(diffMs / 60_000);
|
|
116
|
+
if (diffMin < 1)
|
|
117
|
+
return "now";
|
|
118
|
+
if (diffMin < 60)
|
|
119
|
+
return `${diffMin}m`;
|
|
120
|
+
const diffH = Math.floor(diffMin / 60);
|
|
121
|
+
if (diffH < 24)
|
|
122
|
+
return `${diffH}h`;
|
|
123
|
+
const diffD = Math.floor(diffH / 24);
|
|
124
|
+
return `${diffD}d`;
|
|
125
|
+
}
|
|
126
|
+
function formatAbsoluteTime(receivedAt) {
|
|
127
|
+
const parsed = Date.parse(receivedAt);
|
|
128
|
+
return Number.isFinite(parsed) ? new Date(parsed).toLocaleString() : "";
|
|
129
|
+
}
|
|
130
|
+
function initialsFor(name) {
|
|
131
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
132
|
+
if (parts.length === 0)
|
|
133
|
+
return "?";
|
|
134
|
+
if (parts.length === 1)
|
|
135
|
+
return parts[0]?.slice(0, 2).toUpperCase() ?? "?";
|
|
136
|
+
return `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase();
|
|
137
|
+
}
|
|
138
|
+
function ChannelChip({ channel, active, count, unread, onClick, }) {
|
|
139
|
+
const style = styleForFilter(channel);
|
|
140
|
+
return (_jsxs("button", { type: "button", onClick: () => onClick(channel), "aria-pressed": active, className: [
|
|
141
|
+
"group inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors",
|
|
142
|
+
active
|
|
143
|
+
? `${style.bg} ${style.text} ring-1 ${style.ring}`
|
|
144
|
+
: "bg-bg-muted/30 text-muted hover:text-txt",
|
|
145
|
+
].join(" "), children: [_jsx("span", { className: `shrink-0 ${active ? style.text : "text-muted/80"}`, children: style.icon }), _jsx("span", { children: style.label }), count > 0 ? (_jsx("span", { className: `ml-0.5 rounded-full px-1.5 text-[10px] tabular-nums ${unread > 0 ? `${style.text} bg-white/4` : "text-muted bg-white/4"}`, children: unread > 0 ? unread : count })) : null] }));
|
|
146
|
+
}
|
|
147
|
+
function GmailAccountChip({ label, active, onClick, }) {
|
|
148
|
+
const style = CHANNEL_STYLES.gmail;
|
|
149
|
+
return (_jsxs("button", { type: "button", onClick: onClick, "aria-pressed": active, className: [
|
|
150
|
+
"inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors",
|
|
151
|
+
active
|
|
152
|
+
? `${style.bg} ${style.text} ring-1 ${style.ring}`
|
|
153
|
+
: "bg-bg-muted/30 text-muted hover:text-txt",
|
|
154
|
+
].join(" "), children: [_jsx("span", { className: `shrink-0 ${active ? style.text : "text-muted/80"}`, children: style.icon }), _jsx("span", { children: label })] }));
|
|
155
|
+
}
|
|
156
|
+
function ThreadRow({ group, selected, onSelect, onReply, showAccountSubtitle, }) {
|
|
157
|
+
const message = group.latestMessage;
|
|
158
|
+
const style = styleFor(message.channel);
|
|
159
|
+
const subject = message.subject?.trim() || `${style.label} message`;
|
|
160
|
+
const score = group.maxPriorityScore ?? message.priorityScore ?? 0;
|
|
161
|
+
const category = group.priorityCategory ?? message.priorityCategory ?? null;
|
|
162
|
+
const isImportant = score >= IMPORTANT_PRIORITY_SCORE_THRESHOLD || category === "important";
|
|
163
|
+
const isPlanning = category === "planning";
|
|
164
|
+
const missedAge = computeMissedAgeMs(message);
|
|
165
|
+
const isMissed = missedAge !== null && score >= MISSED_MIN_PRIORITY;
|
|
166
|
+
const senderLabel = group.chatType === "group" && typeof group.participantCount === "number"
|
|
167
|
+
? `${message.sender.displayName} (${group.participantCount})`
|
|
168
|
+
: message.sender.displayName;
|
|
169
|
+
return (_jsxs("div", { role: "option", "aria-selected": selected, tabIndex: 0, onClick: onSelect, onKeyDown: (e) => {
|
|
170
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
171
|
+
e.preventDefault();
|
|
172
|
+
onSelect();
|
|
173
|
+
}
|
|
174
|
+
}, className: [
|
|
175
|
+
"group flex cursor-pointer items-start gap-3 border-l-2 px-3 py-2.5 transition-colors",
|
|
176
|
+
selected
|
|
177
|
+
? "border-accent bg-accent/8"
|
|
178
|
+
: message.unread
|
|
179
|
+
? "border-transparent bg-bg/30 hover:bg-bg-muted/30"
|
|
180
|
+
: "border-transparent hover:bg-bg-muted/20",
|
|
181
|
+
].join(" "), children: [_jsxs("div", { className: "relative h-8 w-8 shrink-0", children: [_jsx("div", { className: `flex h-full w-full items-center justify-center overflow-hidden rounded-full text-[11px] font-semibold ${style.bg} ${style.text}`, children: message.sender.avatarUrl ? (_jsx("img", { src: message.sender.avatarUrl, alt: "", "aria-hidden": true, className: "h-full w-full object-cover" })) : (initialsFor(message.sender.displayName)) }), _jsx("span", { className: `pointer-events-none absolute -bottom-1 -right-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-bg ring-2 ring-bg ${style.text} [&>svg]:h-2.5 [&>svg]:w-2.5`, "aria-hidden": true, children: style.icon })] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [_jsx("span", { className: `truncate text-sm ${message.unread
|
|
182
|
+
? "font-semibold text-txt"
|
|
183
|
+
: "font-medium text-txt/85"}`, children: senderLabel }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [group.totalCount > 1 ? (_jsx("span", { className: "text-[10px] tabular-nums text-muted", children: group.totalCount })) : null, group.unreadCount > 0 ? (_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-accent" })) : null, _jsx("span", { className: "text-[10px] tabular-nums text-muted", children: formatRelativeTime(message.receivedAt) })] })] }), _jsx("div", { className: "mt-0.5 truncate text-xs text-muted", children: subject }), _jsx("div", { className: "mt-0.5 line-clamp-1 text-[11px] text-muted/70", children: message.snippet }), _jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-1.5", children: [isImportant ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-500/16 px-1.5 py-0.5 text-[10px] font-semibold text-amber-300 ring-1 ring-amber-500/40", title: `Priority score ${score}`, children: [_jsx(Sparkles, { className: "h-2.5 w-2.5", "aria-hidden": true }), "Important"] })) : null, isPlanning ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-sky-500/16 px-1.5 py-0.5 text-[10px] font-semibold text-sky-300 ring-1 ring-sky-500/40", children: [_jsx(CalendarClock, { className: "h-2.5 w-2.5", "aria-hidden": true }), "Planning"] })) : null, showAccountSubtitle && message.gmailAccountEmail ? (_jsx("span", { className: "truncate text-[10px] text-muted/70", children: message.gmailAccountEmail })) : null] })] }), _jsxs("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [isMissed && missedAge !== null ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-500/16 px-1.5 py-0.5 text-[10px] font-semibold text-amber-300 ring-1 ring-amber-500/40", title: "Unreplied for over 24h", children: [_jsx(AlarmClock, { className: "h-2.5 w-2.5", "aria-hidden": true }), "Missed \u00B7 ", formatMissedAge(missedAge)] })) : null, _jsx("button", { type: "button", "aria-label": "Reply", onClick: (e) => {
|
|
184
|
+
e.stopPropagation();
|
|
185
|
+
onReply();
|
|
186
|
+
}, className: "mt-0.5 rounded-full p-1.5 text-muted opacity-0 transition-opacity hover:bg-bg-muted/40 hover:text-txt group-hover:opacity-100", children: _jsx(MessageSquareReply, { className: "h-3.5 w-3.5" }) })] })] }));
|
|
187
|
+
}
|
|
188
|
+
function MessageRow({ message, selected, onSelect, onReply, }) {
|
|
189
|
+
const style = styleFor(message.channel);
|
|
190
|
+
const subject = message.subject?.trim() || `${style.label} message`;
|
|
191
|
+
return (_jsxs("div", { role: "option", "aria-selected": selected, tabIndex: 0, onClick: onSelect, onKeyDown: (e) => {
|
|
192
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
onSelect();
|
|
195
|
+
}
|
|
196
|
+
}, className: [
|
|
197
|
+
"group flex cursor-pointer items-start gap-3 border-l-2 px-3 py-2.5 transition-colors",
|
|
198
|
+
selected
|
|
199
|
+
? "border-accent bg-accent/8"
|
|
200
|
+
: message.unread
|
|
201
|
+
? "border-transparent bg-bg/30 hover:bg-bg-muted/30"
|
|
202
|
+
: "border-transparent hover:bg-bg-muted/20",
|
|
203
|
+
].join(" "), children: [_jsxs("div", { className: "relative h-8 w-8 shrink-0", children: [_jsx("div", { className: `flex h-full w-full items-center justify-center overflow-hidden rounded-full text-[11px] font-semibold ${style.bg} ${style.text}`, children: message.sender.avatarUrl ? (_jsx("img", { src: message.sender.avatarUrl, alt: "", "aria-hidden": true, className: "h-full w-full object-cover" })) : (initialsFor(message.sender.displayName)) }), _jsx("span", { className: `pointer-events-none absolute -bottom-1 -right-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-bg ring-2 ring-bg ${style.text} [&>svg]:h-2.5 [&>svg]:w-2.5`, "aria-hidden": true, children: style.icon })] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [_jsx("span", { className: `truncate text-sm ${message.unread
|
|
204
|
+
? "font-semibold text-txt"
|
|
205
|
+
: "font-medium text-txt/85"}`, children: message.sender.displayName }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [message.unread ? (_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-accent" })) : null, _jsx("span", { className: "text-[10px] tabular-nums text-muted", children: formatRelativeTime(message.receivedAt) })] })] }), _jsx("div", { className: "mt-0.5 truncate text-xs text-muted", children: subject }), _jsx("div", { className: "mt-0.5 line-clamp-1 text-[11px] text-muted/70", children: message.snippet })] }), _jsx("button", { type: "button", "aria-label": "Reply", onClick: (e) => {
|
|
206
|
+
e.stopPropagation();
|
|
207
|
+
onReply();
|
|
208
|
+
}, className: "mt-0.5 shrink-0 rounded-full p-1.5 text-muted opacity-0 transition-opacity hover:bg-bg-muted/40 hover:text-txt group-hover:opacity-100", children: _jsx(MessageSquareReply, { className: "h-3.5 w-3.5" }) })] }));
|
|
209
|
+
}
|
|
210
|
+
function ReaderPane({ threadGroup, onReply, onChat, onBack, }) {
|
|
211
|
+
const { t } = useApp();
|
|
212
|
+
const message = threadGroup?.latestMessage ?? null;
|
|
213
|
+
if (!message) {
|
|
214
|
+
return (_jsx("div", { className: "flex flex-1 items-center justify-center bg-bg/20 text-xs text-muted", children: _jsxs("div", { className: "flex flex-col items-center gap-2 text-center", children: [_jsx(MessageSquare, { className: "h-6 w-6 text-muted/50", "aria-hidden": true }), t("lifeopsInbox.selectMessage", {
|
|
215
|
+
defaultValue: "Select a message",
|
|
216
|
+
})] }) }));
|
|
217
|
+
}
|
|
218
|
+
const style = styleFor(message.channel);
|
|
219
|
+
const subject = message.subject?.trim() || `${style.label} message`;
|
|
220
|
+
const receivedAt = formatAbsoluteTime(message.receivedAt);
|
|
221
|
+
const threadMessages = threadGroup
|
|
222
|
+
? [...messagesForThreadGroup(threadGroup)].sort((left, right) => Date.parse(left.receivedAt) - Date.parse(right.receivedAt))
|
|
223
|
+
: [];
|
|
224
|
+
return (_jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-bg/10", children: [_jsxs("div", { className: "flex items-start gap-3 border-b border-border/12 px-5 py-4", children: [onBack ? (_jsx("button", { type: "button", "aria-label": t("lifeopsInbox.backToList", {
|
|
225
|
+
defaultValue: "Back to inbox list",
|
|
226
|
+
}), onClick: onBack, className: "mt-0.5 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted transition-colors hover:bg-bg-muted/40 hover:text-txt", children: _jsx(ArrowLeft, { className: "h-4 w-4" }) })) : null, _jsx("div", { className: `flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-full text-xs font-semibold ${style.bg} ${style.text}`, children: message.sender.avatarUrl ? (_jsx("img", { src: message.sender.avatarUrl, alt: "", "aria-hidden": true, className: "h-full w-full object-cover" })) : (initialsFor(message.sender.displayName)) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-base font-semibold text-txt", children: subject }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-2 text-xs text-muted", children: [_jsxs("span", { className: `inline-flex items-center gap-1 ${style.text}`, children: [style.icon, style.label] }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: threadMessages.length > 1
|
|
227
|
+
? `${threadMessages.length} messages`
|
|
228
|
+
: message.sender.displayName }), receivedAt ? (_jsxs(_Fragment, { children: [_jsx("span", { children: "\u00B7" }), _jsx("span", { children: receivedAt })] })) : null] })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-5 py-4", children: _jsx("div", { className: "space-y-3", children: (threadMessages.length > 0 ? threadMessages : [message]).map((item) => {
|
|
229
|
+
const itemStyle = styleFor(item.channel);
|
|
230
|
+
return (_jsxs("article", { className: "rounded-xl border border-border/12 bg-bg/20 px-3 py-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-medium text-txt", children: item.sender.displayName }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-1.5 text-[11px] text-muted", children: [_jsxs("span", { className: `inline-flex items-center gap-1 ${itemStyle.text}`, children: [itemStyle.icon, itemStyle.label] }), item.sender.email ? _jsx("span", { children: item.sender.email }) : null] })] }), _jsx("span", { className: "shrink-0 text-[11px] tabular-nums text-muted", children: formatAbsoluteTime(item.receivedAt) })] }), _jsx("p", { className: "mt-3 whitespace-pre-wrap text-sm leading-relaxed text-txt/85", children: item.snippet })] }, item.id));
|
|
231
|
+
}) }) }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 border-t border-border/12 px-5 py-3", children: [_jsxs(Button, { size: "sm", className: "h-8 rounded-xl px-3 text-xs font-semibold", onClick: () => onReply(message), children: [_jsx(MessageSquareReply, { className: "mr-1.5 h-3.5 w-3.5" }), t("lifeopsInbox.reply", { defaultValue: "Reply" })] }), _jsxs(Button, { size: "sm", variant: "ghost", className: "h-8 rounded-xl px-3 text-xs font-semibold text-muted", onClick: () => onChat(message), children: [_jsx(MessageSquare, { className: "mr-1.5 h-3.5 w-3.5" }), t("common.chat", { defaultValue: "Chat" })] }), message.channel === "gmail" ? (_jsx(InboxUnsubscribeButton, { message: message })) : null, message.deepLink ? (_jsxs(Button, { size: "sm", variant: "ghost", className: "h-8 rounded-xl px-3 text-xs font-semibold text-muted", onClick: () => message.deepLink && void openExternalUrl(message.deepLink), children: [_jsx(ExternalLink, { className: "mr-1.5 h-3.5 w-3.5" }), t("lifeopsInbox.openSource", { defaultValue: "Open source" })] })) : null] })] }));
|
|
232
|
+
}
|
|
233
|
+
function InboxUnsubscribeButton({ message, }) {
|
|
234
|
+
const senderEmail = message.sender.email?.trim().toLowerCase() || null;
|
|
235
|
+
const [state, setState] = useState("idle");
|
|
236
|
+
const [note, setNote] = useState(null);
|
|
237
|
+
const onClick = useCallback(async () => {
|
|
238
|
+
if (!senderEmail)
|
|
239
|
+
return;
|
|
240
|
+
if (!window.confirm(`Unsubscribe from ${senderEmail} and create a Gmail filter that auto-trashes future mail?`)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
setState("working");
|
|
244
|
+
try {
|
|
245
|
+
const result = await client.unsubscribeLifeOpsEmailSender({
|
|
246
|
+
senderEmail,
|
|
247
|
+
blockAfter: true,
|
|
248
|
+
trashExisting: false,
|
|
249
|
+
confirmed: true,
|
|
250
|
+
});
|
|
251
|
+
setState(result.record.status === "succeeded" ? "done" : "error");
|
|
252
|
+
setNote(result.record.status);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
setState("error");
|
|
256
|
+
setNote(error instanceof Error ? error.message : String(error));
|
|
257
|
+
}
|
|
258
|
+
}, [senderEmail]);
|
|
259
|
+
// Hide entirely when the message has no parsed From email (chat channels,
|
|
260
|
+
// malformed Gmail headers). Showing a button that can't work is worse than
|
|
261
|
+
// not showing it.
|
|
262
|
+
if (!senderEmail)
|
|
263
|
+
return null;
|
|
264
|
+
const label = state === "working"
|
|
265
|
+
? "Unsubscribing…"
|
|
266
|
+
: state === "done"
|
|
267
|
+
? "Unsubscribed"
|
|
268
|
+
: state === "error"
|
|
269
|
+
? `Failed${note ? `: ${note}` : ""}`
|
|
270
|
+
: "Unsubscribe";
|
|
271
|
+
return (_jsx(Button, { size: "sm", variant: "ghost", className: "h-8 rounded-xl px-3 text-xs font-semibold text-muted", disabled: state === "working" || state === "done", onClick: () => void onClick(), title: `Send RFC 8058 one-click unsubscribe to ${senderEmail} and create a Gmail filter`, children: label }));
|
|
272
|
+
}
|
|
273
|
+
function InboxListPane({ inbox, selectedMessageId, onSelect, onReply, emptyLabel, groupedMode, visibleThreadGroups, showGmailAccountSubtitles, }) {
|
|
274
|
+
const { t } = useApp();
|
|
275
|
+
const isEmpty = groupedMode
|
|
276
|
+
? visibleThreadGroups.length === 0
|
|
277
|
+
: inbox.messages.length === 0;
|
|
278
|
+
return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "border-b border-border/10 px-3 py-2", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-2.5 top-2 h-3.5 w-3.5 text-muted" }), _jsx(Input, { value: inbox.searchQuery, onChange: (e) => inbox.setSearchQuery(e.target.value), placeholder: t("lifeopsInbox.search", {
|
|
279
|
+
defaultValue: "Search…",
|
|
280
|
+
}), "aria-label": t("lifeopsInbox.searchAria", {
|
|
281
|
+
defaultValue: "Search inbox",
|
|
282
|
+
}), className: "h-8 pl-8 text-xs" })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", role: "listbox", "aria-label": t("lifeopsInbox.listAria", {
|
|
283
|
+
defaultValue: "Messages",
|
|
284
|
+
}), children: isEmpty ? (_jsx("div", { className: "px-4 py-8 text-center text-xs text-muted", children: inbox.searchQuery
|
|
285
|
+
? t("lifeopsInbox.noResults", {
|
|
286
|
+
defaultValue: "No matches.",
|
|
287
|
+
})
|
|
288
|
+
: t("lifeopsInbox.empty", {
|
|
289
|
+
defaultValue: emptyLabel ?? "Inbox clear.",
|
|
290
|
+
}) })) : groupedMode ? (visibleThreadGroups.map((group) => (_jsx(ThreadRow, { group: group, selected: group.latestMessage.id === selectedMessageId ||
|
|
291
|
+
messagesForThreadGroup(group).some((message) => message.id === selectedMessageId), onSelect: () => onSelect({ messageId: group.latestMessage.id }), onReply: () => onReply(group.latestMessage), showAccountSubtitle: showGmailAccountSubtitles }, group.threadId)))) : (inbox.messages.map((msg) => (_jsx(MessageRow, { message: msg, selected: msg.id === selectedMessageId, onSelect: () => onSelect({ messageId: msg.id }), onReply: () => onReply(msg) }, msg.id)))) })] }));
|
|
292
|
+
}
|
|
293
|
+
export function LifeOpsInboxSection(props = {}) {
|
|
294
|
+
const ctx = useLifeOpsSelection();
|
|
295
|
+
const selection = props.selection ?? ctx.selection;
|
|
296
|
+
const onSelect = props.onSelect ?? ctx.select;
|
|
297
|
+
const { t } = useApp();
|
|
298
|
+
const { openLifeOpsChat } = useLifeOpsChatLauncher();
|
|
299
|
+
const compactLayout = useMediaQuery("(max-width: 767px)");
|
|
300
|
+
const allowedChannels = props.channels ?? LIFEOPS_INBOX_CHANNELS;
|
|
301
|
+
// Derive the section mode from the channel set passed in by the route.
|
|
302
|
+
// Mail mode is gmail-only; everything else is the Messages section, which
|
|
303
|
+
// hides public channels and groups with more than 15 participants.
|
|
304
|
+
const isMailMode = allowedChannels.length === 1 && allowedChannels[0] === "gmail";
|
|
305
|
+
const isMessagesMode = !isMailMode;
|
|
306
|
+
const channelFilters = useMemo(() => allowedChannels.length > 1
|
|
307
|
+
? ["all", ...allowedChannels]
|
|
308
|
+
: [...allowedChannels], [allowedChannels]);
|
|
309
|
+
const [selectedGmailAccount, setSelectedGmailAccount] = useState(ALL_GMAIL_ACCOUNTS);
|
|
310
|
+
const [missedOnly, setMissedOnly] = useState(false);
|
|
311
|
+
const chatTypeFilter = useMemo(() => isMessagesMode
|
|
312
|
+
? ["dm", "group"]
|
|
313
|
+
: isMailMode
|
|
314
|
+
? ["dm"]
|
|
315
|
+
: undefined, [isMessagesMode, isMailMode]);
|
|
316
|
+
const inbox = useInbox({
|
|
317
|
+
maxResults: 40,
|
|
318
|
+
channel: allowedChannels.length === 1 ? allowedChannels[0] : "all",
|
|
319
|
+
channels: allowedChannels,
|
|
320
|
+
groupByThread: true,
|
|
321
|
+
chatTypeFilter,
|
|
322
|
+
maxParticipants: isMessagesMode ? SMALL_GROUP_PARTICIPANT_CAP : undefined,
|
|
323
|
+
gmailAccountId: isMailMode && selectedGmailAccount !== ALL_GMAIL_ACCOUNTS
|
|
324
|
+
? selectedGmailAccount
|
|
325
|
+
: undefined,
|
|
326
|
+
missedOnly: isMessagesMode ? missedOnly : false,
|
|
327
|
+
// Mail mode keeps recency-first because email priority is less actionable.
|
|
328
|
+
sortByPriority: isMessagesMode,
|
|
329
|
+
});
|
|
330
|
+
const selectedMessageId = selection.messageId ?? null;
|
|
331
|
+
// Build the messages-by-id index from both flat messages and thread groups
|
|
332
|
+
// so the reader pane can resolve the active message regardless of how we
|
|
333
|
+
// ended up selecting it.
|
|
334
|
+
const messageById = useMemo(() => {
|
|
335
|
+
const map = new Map();
|
|
336
|
+
for (const msg of inbox.messages)
|
|
337
|
+
map.set(msg.id, msg);
|
|
338
|
+
for (const group of inbox.threadGroups) {
|
|
339
|
+
map.set(group.latestMessage.id, group.latestMessage);
|
|
340
|
+
for (const msg of messagesForThreadGroup(group)) {
|
|
341
|
+
map.set(msg.id, msg);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return map;
|
|
345
|
+
}, [inbox.messages, inbox.threadGroups]);
|
|
346
|
+
const threadGroupByMessageId = useMemo(() => {
|
|
347
|
+
const map = new Map();
|
|
348
|
+
for (const group of inbox.threadGroups) {
|
|
349
|
+
map.set(group.latestMessage.id, group);
|
|
350
|
+
for (const msg of messagesForThreadGroup(group)) {
|
|
351
|
+
map.set(msg.id, group);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return map;
|
|
355
|
+
}, [inbox.threadGroups]);
|
|
356
|
+
const selectedMessage = (selectedMessageId ? messageById.get(selectedMessageId) : null) ?? null;
|
|
357
|
+
const selectedThread = (selectedMessageId ? threadGroupByMessageId.get(selectedMessageId) : null) ??
|
|
358
|
+
null;
|
|
359
|
+
// Distinct Gmail accounts visible in the current feed. Only show the chip
|
|
360
|
+
// group when more than one Gmail account has produced messages.
|
|
361
|
+
const gmailAccountOptions = useMemo(() => {
|
|
362
|
+
if (!isMailMode)
|
|
363
|
+
return [];
|
|
364
|
+
const seen = new Map();
|
|
365
|
+
for (const group of inbox.threadGroups) {
|
|
366
|
+
const id = group.latestMessage.gmailAccountId;
|
|
367
|
+
const email = group.latestMessage.gmailAccountEmail;
|
|
368
|
+
if (id && email && !seen.has(id))
|
|
369
|
+
seen.set(id, email);
|
|
370
|
+
}
|
|
371
|
+
if (seen.size === 0) {
|
|
372
|
+
for (const msg of inbox.messages) {
|
|
373
|
+
if (msg.gmailAccountId &&
|
|
374
|
+
msg.gmailAccountEmail &&
|
|
375
|
+
!seen.has(msg.gmailAccountId)) {
|
|
376
|
+
seen.set(msg.gmailAccountId, msg.gmailAccountEmail);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return Array.from(seen.entries()).map(([id, label]) => ({ id, label }));
|
|
381
|
+
}, [inbox.threadGroups, inbox.messages, isMailMode]);
|
|
382
|
+
const showGmailAccountChips = isMailMode && gmailAccountOptions.length > 1;
|
|
383
|
+
// Subtitle on every Gmail row when more than one account is connected, so
|
|
384
|
+
// users can tell apart two senders that exist in both inboxes.
|
|
385
|
+
const showGmailAccountSubtitles = showGmailAccountChips;
|
|
386
|
+
// Reset to "all" if the previously selected account disappears from the
|
|
387
|
+
// current feed (e.g. account disconnected).
|
|
388
|
+
useEffect(() => {
|
|
389
|
+
if (selectedGmailAccount !== ALL_GMAIL_ACCOUNTS &&
|
|
390
|
+
!gmailAccountOptions.some((opt) => opt.id === selectedGmailAccount)) {
|
|
391
|
+
setSelectedGmailAccount(ALL_GMAIL_ACCOUNTS);
|
|
392
|
+
}
|
|
393
|
+
}, [gmailAccountOptions, selectedGmailAccount]);
|
|
394
|
+
const channelCounts = useMemo(() => {
|
|
395
|
+
const base = Object.fromEntries(channelFilters.map((channel) => [channel, { total: 0, unread: 0 }]));
|
|
396
|
+
for (const message of inbox.messages) {
|
|
397
|
+
const all = base.all;
|
|
398
|
+
if (all) {
|
|
399
|
+
all.total++;
|
|
400
|
+
if (message.unread)
|
|
401
|
+
all.unread++;
|
|
402
|
+
}
|
|
403
|
+
const bucket = base[message.channel];
|
|
404
|
+
if (bucket) {
|
|
405
|
+
bucket.total++;
|
|
406
|
+
if (message.unread)
|
|
407
|
+
bucket.unread++;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return base;
|
|
411
|
+
}, [channelFilters, inbox.messages]);
|
|
412
|
+
// Build the navigable list (thread rows in grouped modes, flat messages
|
|
413
|
+
// otherwise) so j/k keyboard navigation walks the same items the user sees.
|
|
414
|
+
const navigableItems = useMemo(() => inbox.threadGroups.map((g) => g.latestMessage), [inbox.threadGroups]);
|
|
415
|
+
const navigableSelectedIndex = useMemo(() => navigableItems.findIndex((m) => m.id === selectedMessageId), [navigableItems, selectedMessageId]);
|
|
416
|
+
const selectByIndex = useCallback((index) => {
|
|
417
|
+
const msg = navigableItems[index];
|
|
418
|
+
if (msg)
|
|
419
|
+
onSelect({ messageId: msg.id });
|
|
420
|
+
}, [navigableItems, onSelect]);
|
|
421
|
+
const handleReply = useCallback((msg) => {
|
|
422
|
+
const label = styleFor(msg.channel).label;
|
|
423
|
+
const text = buildReplyPrefill({
|
|
424
|
+
channel: msg.channel === "gmail" ? "email" : label,
|
|
425
|
+
sender: msg.sender.displayName,
|
|
426
|
+
snippet: msg.snippet,
|
|
427
|
+
deepLink: msg.deepLink,
|
|
428
|
+
});
|
|
429
|
+
openLifeOpsChat(text, { messageId: msg.id });
|
|
430
|
+
}, [openLifeOpsChat]);
|
|
431
|
+
const handleChat = useCallback((msg) => {
|
|
432
|
+
openLifeOpsChat(buildMessageChatPrefill(msg), {
|
|
433
|
+
messageId: msg.id,
|
|
434
|
+
});
|
|
435
|
+
}, [openLifeOpsChat]);
|
|
436
|
+
useEffect(() => {
|
|
437
|
+
const handler = (e) => {
|
|
438
|
+
const tag = e.target.tagName;
|
|
439
|
+
if (tag === "INPUT" ||
|
|
440
|
+
tag === "TEXTAREA" ||
|
|
441
|
+
e.target.isContentEditable) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (e.key === "j") {
|
|
445
|
+
e.preventDefault();
|
|
446
|
+
selectByIndex(Math.min(navigableSelectedIndex + 1, navigableItems.length - 1));
|
|
447
|
+
}
|
|
448
|
+
else if (e.key === "k") {
|
|
449
|
+
e.preventDefault();
|
|
450
|
+
selectByIndex(Math.max(navigableSelectedIndex - 1, 0));
|
|
451
|
+
}
|
|
452
|
+
else if (e.key === "r" && selectedMessage) {
|
|
453
|
+
e.preventDefault();
|
|
454
|
+
handleReply(selectedMessage);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
window.addEventListener("keydown", handler);
|
|
458
|
+
return () => window.removeEventListener("keydown", handler);
|
|
459
|
+
}, [
|
|
460
|
+
handleReply,
|
|
461
|
+
navigableItems.length,
|
|
462
|
+
navigableSelectedIndex,
|
|
463
|
+
selectByIndex,
|
|
464
|
+
selectedMessage,
|
|
465
|
+
]);
|
|
466
|
+
useEffect(() => {
|
|
467
|
+
if (!compactLayout &&
|
|
468
|
+
navigableItems.length > 0 &&
|
|
469
|
+
(!selectedMessageId || navigableSelectedIndex === -1)) {
|
|
470
|
+
onSelect({ messageId: navigableItems[0].id });
|
|
471
|
+
}
|
|
472
|
+
}, [
|
|
473
|
+
compactLayout,
|
|
474
|
+
navigableItems,
|
|
475
|
+
navigableSelectedIndex,
|
|
476
|
+
onSelect,
|
|
477
|
+
selectedMessageId,
|
|
478
|
+
]);
|
|
479
|
+
return (_jsxs("section", { className: "flex h-full min-h-0 flex-col overflow-hidden rounded-3xl border border-border/16 bg-card/18", "data-testid": "lifeops-inbox-section", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-border/12 px-3 py-2.5", children: [_jsx("div", { className: "mr-auto px-1 text-sm font-semibold text-txt", children: props.title ?? "Messages" }), channelFilters.map((ch) => {
|
|
480
|
+
const counts = channelCounts[ch];
|
|
481
|
+
return (_jsx(ChannelChip, { channel: ch, active: inbox.channel === ch, count: counts?.total ?? 0, unread: counts?.unread ?? 0, onClick: inbox.setChannel }, ch));
|
|
482
|
+
}), isMessagesMode ? (_jsxs("button", { type: "button", "aria-pressed": missedOnly, onClick: () => setMissedOnly((prev) => !prev), title: t("lifeopsInbox.missedTooltip", {
|
|
483
|
+
defaultValue: "Threads you have not replied to in 24h with priority ≥ 50",
|
|
484
|
+
}), className: [
|
|
485
|
+
"inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors",
|
|
486
|
+
missedOnly
|
|
487
|
+
? "bg-amber-500/16 text-amber-300 ring-1 ring-amber-500/40"
|
|
488
|
+
: "bg-bg-muted/30 text-muted hover:text-txt",
|
|
489
|
+
].join(" "), children: [_jsx(AlarmClock, { className: "h-3.5 w-3.5", "aria-hidden": true }), t("lifeopsInbox.missed", { defaultValue: "Missed" })] })) : null] }), showGmailAccountChips ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-border/10 px-3 py-2", children: [_jsx(GmailAccountChip, { label: t("lifeopsInbox.allGmail", { defaultValue: "All Gmail" }), active: selectedGmailAccount === ALL_GMAIL_ACCOUNTS, onClick: () => setSelectedGmailAccount(ALL_GMAIL_ACCOUNTS) }), gmailAccountOptions.map((opt) => (_jsx(GmailAccountChip, { label: `Gmail · ${opt.label}`, active: selectedGmailAccount === opt.id, onClick: () => setSelectedGmailAccount(opt.id) }, opt.id)))] })) : null, inbox.error ? (_jsx("div", { className: "px-5 py-4 text-xs text-rose-300", children: inbox.error })) : inbox.loading && inbox.messages.length === 0 ? (_jsxs("div", { className: "flex items-center gap-2 px-5 py-8 text-xs text-muted", children: [_jsx(Spinner, { size: 14 }), t("lifeopsInbox.loading", { defaultValue: "Loading inbox…" })] })) : (_jsx("div", { className: "flex min-h-0 flex-1", children: compactLayout ? (selectedThread ? (_jsx(ReaderPane, { threadGroup: selectedThread, onReply: handleReply, onChat: handleChat, onBack: () => onSelect({ messageId: null }) })) : (_jsx(InboxListPane, { inbox: inbox, selectedMessageId: selectedMessageId, onSelect: onSelect, onReply: handleReply, emptyLabel: props.emptyLabel, groupedMode: true, visibleThreadGroups: inbox.threadGroups, showGmailAccountSubtitles: showGmailAccountSubtitles }))) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex w-72 shrink-0 flex-col border-r border-border/12", children: _jsx(InboxListPane, { inbox: inbox, selectedMessageId: selectedMessageId, onSelect: onSelect, onReply: handleReply, emptyLabel: props.emptyLabel, groupedMode: true, visibleThreadGroups: inbox.threadGroups, showGmailAccountSubtitles: showGmailAccountSubtitles }) }), _jsx(ReaderPane, { threadGroup: selectedThread, onReply: handleReply, onChat: handleChat })] })) }))] }));
|
|
490
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type JSX } from "react";
|
|
2
|
+
import type { LifeOpsPaymentSource } from "../lifeops/payment-types.js";
|
|
3
|
+
interface LifeOpsLinkBankButtonProps {
|
|
4
|
+
onLinked?: (source: LifeOpsPaymentSource) => void;
|
|
5
|
+
/** Optional override for the trigger label. Default: "Link bank with Plaid". */
|
|
6
|
+
label?: string;
|
|
7
|
+
/** Optional override for the disabled-state title. */
|
|
8
|
+
unavailableTitle?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function LifeOpsLinkBankButton({ onLinked, label, unavailableTitle, }: LifeOpsLinkBankButtonProps): JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=LifeOpsLinkBankButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LifeOpsLinkBankButton.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/components/LifeOpsLinkBankButton.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAE,KAAK,GAAG,EAAoC,MAAM,OAAO,CAAC;AAEnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,UAAU,0BAA0B;IAClC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAClD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,KAA8B,EAC9B,gBAAmH,GACpH,EAAE,0BAA0B,GAAG,GAAG,CAAC,OAAO,CAyG1C"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* LifeOpsLinkBankButton — drives the Plaid Link flow for the Money page.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. On mount of the modal, fetch a fresh `link_token` from Eliza Cloud via
|
|
7
|
+
* `client.createLifeOpsPlaidLinkToken()`.
|
|
8
|
+
* 2. Hand that token to `usePlaidLink` so the Plaid Link UI can drive the
|
|
9
|
+
* bank-selection / login / account-picker flow client-side.
|
|
10
|
+
* 3. On `onSuccess(public_token)`, exchange the token via
|
|
11
|
+
* `client.completeLifeOpsPlaidLink({ publicToken })`. Eliza Cloud
|
|
12
|
+
* exchanges the public_token for a long-lived `access_token`, never
|
|
13
|
+
* surfaces the secret to the browser, and we get back a fresh
|
|
14
|
+
* payment-source row.
|
|
15
|
+
* 4. Caller's `onLinked` runs the dashboard refresh.
|
|
16
|
+
*
|
|
17
|
+
* The Plaid `link_token` is short-lived; if the user opens the modal but
|
|
18
|
+
* cancels, we re-fetch on the next attempt. We do NOT persist link_tokens.
|
|
19
|
+
*/
|
|
20
|
+
import { client, useApp } from "@elizaos/app-core";
|
|
21
|
+
import { Banknote, Loader2 } from "lucide-react";
|
|
22
|
+
import { useCallback, useEffect, useState } from "react";
|
|
23
|
+
import { usePlaidLink } from "react-plaid-link";
|
|
24
|
+
export function LifeOpsLinkBankButton({ onLinked, label = "Link bank with Plaid", unavailableTitle = "Plaid link is not available — Eliza Cloud not connected, or PLAID_* env vars not set in cloud.", }) {
|
|
25
|
+
const { elizaCloudConnected } = useApp();
|
|
26
|
+
const [linkToken, setLinkToken] = useState(null);
|
|
27
|
+
const [tokenError, setTokenError] = useState(null);
|
|
28
|
+
const [tokenLoading, setTokenLoading] = useState(false);
|
|
29
|
+
const [exchangeStatus, setExchangeStatus] = useState("idle");
|
|
30
|
+
const [exchangeError, setExchangeError] = useState(null);
|
|
31
|
+
const fetchLinkToken = useCallback(async () => {
|
|
32
|
+
setTokenLoading(true);
|
|
33
|
+
setTokenError(null);
|
|
34
|
+
try {
|
|
35
|
+
const data = await client.createLifeOpsPlaidLinkToken();
|
|
36
|
+
setLinkToken(data.linkToken);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
setTokenError(err instanceof Error ? err.message : String(err));
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
setTokenLoading(false);
|
|
43
|
+
}
|
|
44
|
+
}, []);
|
|
45
|
+
const onSuccess = useCallback(async (publicToken, _metadata) => {
|
|
46
|
+
setExchangeStatus("exchanging");
|
|
47
|
+
setExchangeError(null);
|
|
48
|
+
try {
|
|
49
|
+
const result = await client.completeLifeOpsPlaidLink({
|
|
50
|
+
publicToken,
|
|
51
|
+
});
|
|
52
|
+
setExchangeStatus("done");
|
|
53
|
+
// Burn the link_token — Plaid only allows it once, and we want a
|
|
54
|
+
// fresh one on the next attempt.
|
|
55
|
+
setLinkToken(null);
|
|
56
|
+
onLinked?.(result.source);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
setExchangeStatus("error");
|
|
60
|
+
setExchangeError(err instanceof Error ? err.message : String(err));
|
|
61
|
+
}
|
|
62
|
+
}, [onLinked]);
|
|
63
|
+
// We feed `usePlaidLink` an empty token when we don't have one yet —
|
|
64
|
+
// the hook tolerates this and just won't be `ready`. This keeps the
|
|
65
|
+
// hook unconditional (rules-of-hooks) and lets us drive opening on
|
|
66
|
+
// demand without two render passes.
|
|
67
|
+
const { open, ready } = usePlaidLink({
|
|
68
|
+
token: linkToken ?? "",
|
|
69
|
+
onSuccess,
|
|
70
|
+
});
|
|
71
|
+
// When we have a token AND Plaid Link is ready, open it automatically.
|
|
72
|
+
// The button click only triggers `fetchLinkToken`; `open()` runs in this
|
|
73
|
+
// effect once Link reports ready.
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (linkToken && ready) {
|
|
76
|
+
open();
|
|
77
|
+
}
|
|
78
|
+
}, [linkToken, ready, open]);
|
|
79
|
+
const onClick = useCallback(() => {
|
|
80
|
+
setExchangeStatus("idle");
|
|
81
|
+
setExchangeError(null);
|
|
82
|
+
void fetchLinkToken();
|
|
83
|
+
}, [fetchLinkToken]);
|
|
84
|
+
const disabled = !elizaCloudConnected || tokenLoading || exchangeStatus === "exchanging";
|
|
85
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("button", { type: "button", onClick: onClick, disabled: disabled, title: !elizaCloudConnected ? unavailableTitle : undefined, className: "inline-flex items-center gap-1.5 rounded-md border border-border/30 bg-bg-muted/30 px-2.5 py-1 text-xs font-medium hover:bg-bg-muted/60 disabled:cursor-not-allowed disabled:opacity-50", children: [tokenLoading || exchangeStatus === "exchanging" ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": true })) : (_jsx(Banknote, { className: "h-3.5 w-3.5", "aria-hidden": true })), exchangeStatus === "exchanging"
|
|
86
|
+
? "Linking…"
|
|
87
|
+
: exchangeStatus === "done"
|
|
88
|
+
? "Linked"
|
|
89
|
+
: tokenLoading
|
|
90
|
+
? "Preparing Plaid…"
|
|
91
|
+
: label] }), tokenError ? (_jsxs("span", { className: "text-[11px] text-rose-300", children: ["Plaid: ", tokenError] })) : null, exchangeError ? (_jsxs("span", { className: "text-[11px] text-rose-300", children: ["Exchange failed: ", exchangeError] })) : null] }));
|
|
92
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type JSX } from "react";
|
|
2
|
+
import type { LifeOpsPaymentSource } from "../lifeops/payment-types.js";
|
|
3
|
+
interface LifeOpsLinkPaypalButtonProps {
|
|
4
|
+
onLinked?: (source: LifeOpsPaymentSource, capability: {
|
|
5
|
+
hasReporting: boolean;
|
|
6
|
+
hasIdentity: boolean;
|
|
7
|
+
}) => void;
|
|
8
|
+
label?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function LifeOpsLinkPaypalButton({ onLinked, label, }: LifeOpsLinkPaypalButtonProps): JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=LifeOpsLinkPaypalButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LifeOpsLinkPaypalButton.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAE,KAAK,GAAG,EAA4C,MAAM,OAAO,CAAC;AAC3E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,UAAU,4BAA4B;IACpC,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,oBAAoB,EAC5B,UAAU,EAAE;QAAE,YAAY,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,KACxD,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqBD,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,KAAqB,GACtB,EAAE,4BAA4B,GAAG,GAAG,CAAC,OAAO,CAwK5C"}
|