@burdenoff/microfe-channel 2026.510.112

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 (156) hide show
  1. package/README.md +147 -0
  2. package/dist/channel/ChannelRoot.d.ts +32 -0
  3. package/dist/channel/ChannelRoot.d.ts.map +1 -0
  4. package/dist/channel/ChannelRoot.js +81 -0
  5. package/dist/channel/ChannelRoot.js.map +1 -0
  6. package/dist/channel/ChannelRoutes.d.ts +10 -0
  7. package/dist/channel/ChannelRoutes.d.ts.map +1 -0
  8. package/dist/channel/ChannelRoutes.js +104 -0
  9. package/dist/channel/ChannelRoutes.js.map +1 -0
  10. package/dist/channel/components/AdapterCredentialsForm.d.ts +20 -0
  11. package/dist/channel/components/AdapterCredentialsForm.d.ts.map +1 -0
  12. package/dist/channel/components/AdapterCredentialsForm.js +230 -0
  13. package/dist/channel/components/AdapterCredentialsForm.js.map +1 -0
  14. package/dist/channel/components/FeatureNotEnabled.d.ts +10 -0
  15. package/dist/channel/components/FeatureNotEnabled.d.ts.map +1 -0
  16. package/dist/channel/components/FeatureNotEnabled.js +32 -0
  17. package/dist/channel/components/FeatureNotEnabled.js.map +1 -0
  18. package/dist/channel/components/PermissionGuard.d.ts +15 -0
  19. package/dist/channel/components/PermissionGuard.d.ts.map +1 -0
  20. package/dist/channel/components/PermissionGuard.js +23 -0
  21. package/dist/channel/components/PermissionGuard.js.map +1 -0
  22. package/dist/channel/config/adapterCredentials.d.ts +44 -0
  23. package/dist/channel/config/adapterCredentials.d.ts.map +1 -0
  24. package/dist/channel/config/adapterCredentials.js +946 -0
  25. package/dist/channel/config/adapterCredentials.js.map +1 -0
  26. package/dist/channel/constants/permissions.d.ts +32 -0
  27. package/dist/channel/constants/permissions.d.ts.map +1 -0
  28. package/dist/channel/constants/permissions.js +30 -0
  29. package/dist/channel/constants/permissions.js.map +1 -0
  30. package/dist/channel/graphql/global-client.d.ts +11 -0
  31. package/dist/channel/graphql/global-client.d.ts.map +1 -0
  32. package/dist/channel/graphql/global-client.js +56 -0
  33. package/dist/channel/graphql/global-client.js.map +1 -0
  34. package/dist/channel/hooks/useChannelOrgSettings.d.ts +22 -0
  35. package/dist/channel/hooks/useChannelOrgSettings.d.ts.map +1 -0
  36. package/dist/channel/hooks/useChannelOrgSettings.js +61 -0
  37. package/dist/channel/hooks/useChannelOrgSettings.js.map +1 -0
  38. package/dist/channel/hooks/useChannelSubscription.d.ts +36 -0
  39. package/dist/channel/hooks/useChannelSubscription.d.ts.map +1 -0
  40. package/dist/channel/hooks/useChannelSubscription.js +111 -0
  41. package/dist/channel/hooks/useChannelSubscription.js.map +1 -0
  42. package/dist/channel/hooks/useChannels.d.ts +214 -0
  43. package/dist/channel/hooks/useChannels.d.ts.map +1 -0
  44. package/dist/channel/hooks/useChannels.js +416 -0
  45. package/dist/channel/hooks/useChannels.js.map +1 -0
  46. package/dist/channel/index.d.ts +12 -0
  47. package/dist/channel/index.d.ts.map +1 -0
  48. package/dist/channel/index.js +2 -0
  49. package/dist/channel/modules/channels/hooks/useExport.d.ts +45 -0
  50. package/dist/channel/modules/channels/hooks/useExport.d.ts.map +1 -0
  51. package/dist/channel/modules/channels/hooks/useExport.js +195 -0
  52. package/dist/channel/modules/channels/hooks/useExport.js.map +1 -0
  53. package/dist/channel/modules/channels/i18n.d.ts +14 -0
  54. package/dist/channel/modules/channels/i18n.d.ts.map +1 -0
  55. package/dist/channel/modules/channels/i18n.js +110 -0
  56. package/dist/channel/modules/channels/i18n.js.map +1 -0
  57. package/dist/channel/modules/channels/pages/ChannelDashboardPage.d.ts +14 -0
  58. package/dist/channel/modules/channels/pages/ChannelDashboardPage.d.ts.map +1 -0
  59. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +680 -0
  60. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -0
  61. package/dist/channel/modules/channels/pages/ChannelDetailsPage.d.ts +7 -0
  62. package/dist/channel/modules/channels/pages/ChannelDetailsPage.d.ts.map +1 -0
  63. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +949 -0
  64. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -0
  65. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts +7 -0
  66. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts.map +1 -0
  67. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +404 -0
  68. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -0
  69. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts +7 -0
  70. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts.map +1 -0
  71. package/dist/channel/modules/channels/pages/ChannelUsersPage.js +315 -0
  72. package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -0
  73. package/dist/channel/modules/channels/pages/ChannelsListPage.d.ts +7 -0
  74. package/dist/channel/modules/channels/pages/ChannelsListPage.d.ts.map +1 -0
  75. package/dist/channel/modules/channels/pages/ChannelsListPage.js +604 -0
  76. package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -0
  77. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts +7 -0
  78. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts.map +1 -0
  79. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +323 -0
  80. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -0
  81. package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts +7 -0
  82. package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts.map +1 -0
  83. package/dist/channel/modules/channels/pages/ConnectionsListPage.js +276 -0
  84. package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -0
  85. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts +12 -0
  86. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts.map +1 -0
  87. package/dist/channel/modules/channels/pages/CreateChannelPage.js +456 -0
  88. package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -0
  89. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts +11 -0
  90. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts.map +1 -0
  91. package/dist/channel/modules/channels/pages/CreateConnectionPage.js +219 -0
  92. package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -0
  93. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts +7 -0
  94. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts.map +1 -0
  95. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +375 -0
  96. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -0
  97. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts +8 -0
  98. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts.map +1 -0
  99. package/dist/channel/modules/channels/pages/EditChannelPage.js +459 -0
  100. package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -0
  101. package/dist/channel/modules/channels/pages/EditConnectionPage.d.ts +10 -0
  102. package/dist/channel/modules/channels/pages/EditConnectionPage.d.ts.map +1 -0
  103. package/dist/channel/modules/channels/pages/EditConnectionPage.js +199 -0
  104. package/dist/channel/modules/channels/pages/EditConnectionPage.js.map +1 -0
  105. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts +8 -0
  106. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts.map +1 -0
  107. package/dist/channel/modules/channels/pages/SendMessagePage.js +403 -0
  108. package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -0
  109. package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts +7 -0
  110. package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts.map +1 -0
  111. package/dist/channel/modules/channels/pages/WebhookEventsPage.js +303 -0
  112. package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -0
  113. package/dist/channel/modules/channels/pages/index.d.ts +18 -0
  114. package/dist/channel/modules/channels/pages/index.d.ts.map +1 -0
  115. package/dist/channel/modules/channels/pages/index.js +14 -0
  116. package/dist/channel/pages/ChannelLandingPage.d.ts +9 -0
  117. package/dist/channel/pages/ChannelLandingPage.d.ts.map +1 -0
  118. package/dist/channel/pages/ChannelLandingPage.js +72 -0
  119. package/dist/channel/pages/ChannelLandingPage.js.map +1 -0
  120. package/dist/channel/providers/ChannelProvider.d.ts +16 -0
  121. package/dist/channel/providers/ChannelProvider.d.ts.map +1 -0
  122. package/dist/channel/providers/ChannelProvider.js +35 -0
  123. package/dist/channel/providers/ChannelProvider.js.map +1 -0
  124. package/dist/channel/types/index.d.ts +89 -0
  125. package/dist/channel/types/index.d.ts.map +1 -0
  126. package/dist/channel/utils/shellBridge.d.ts +59 -0
  127. package/dist/channel/utils/shellBridge.d.ts.map +1 -0
  128. package/dist/channel/utils/shellBridge.js +36 -0
  129. package/dist/channel/utils/shellBridge.js.map +1 -0
  130. package/dist/dev/App.d.ts +6 -0
  131. package/dist/dev/App.d.ts.map +1 -0
  132. package/dist/dev/main.d.ts +2 -0
  133. package/dist/dev/main.d.ts.map +1 -0
  134. package/dist/generated/global-operations.d.ts +1547 -0
  135. package/dist/generated/global-operations.d.ts.map +1 -0
  136. package/dist/generated/global-operations.js +466 -0
  137. package/dist/generated/global-operations.js.map +1 -0
  138. package/dist/generated/global-types.d.ts +21289 -0
  139. package/dist/generated/global-types.d.ts.map +1 -0
  140. package/dist/generated/global-types.js +14 -0
  141. package/dist/generated/global-types.js.map +1 -0
  142. package/dist/generated/wspace-operations.d.ts +2 -0
  143. package/dist/generated/wspace-operations.d.ts.map +1 -0
  144. package/dist/generated/wspace-types.d.ts +55214 -0
  145. package/dist/generated/wspace-types.d.ts.map +1 -0
  146. package/dist/index.d.ts +5 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +4 -0
  149. package/dist/node_modules/@apollo/client/errors/CombinedGraphQLErrors.js +24 -0
  150. package/dist/node_modules/@apollo/client/errors/CombinedGraphQLErrors.js.map +1 -0
  151. package/dist/node_modules/@apollo/client/errors/utils.js +16 -0
  152. package/dist/node_modules/@apollo/client/errors/utils.js.map +1 -0
  153. package/dist/utils/nativeBridge.d.ts +3 -0
  154. package/dist/utils/nativeBridge.d.ts.map +1 -0
  155. package/dist/utils/nativeBridge.js +2 -0
  156. package/package.json +116 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeliveryHistoryPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/DeliveryHistoryPage.tsx"],"sourcesContent":["/**\n * Delivery History Page\n *\n * Displays message delivery attempts for a specific channel with retry capability\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ArrowLeft,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n Clock,\n RefreshCw,\n Send,\n RotateCcw,\n Download,\n} from 'lucide-react';\nimport { useChannel, type DeliveryStatus, type DeliveryAttempt } from '../../../hooks/useChannels';\nimport { useChannel as useChannelContext } from '../../../providers/ChannelProvider';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\nimport {\n DELIVERY_UPDATED_SUBSCRIPTION,\n useChannelSubscription,\n} from '../../../hooks/useChannelSubscription';\nimport { useExportDeliveryAttempts } from '../hooks/useExport';\n\nconst STATUS_CONFIG: Record<\n DeliveryStatus,\n { label: string; color: string; icon: typeof CheckCircle2 }\n> = {\n PENDING: { label: 'Pending', color: 'text-muted-foreground bg-muted', icon: Clock },\n QUEUED: { label: 'Queued', color: 'text-info-500 bg-info-100', icon: Clock },\n SENDING: { label: 'Sending', color: 'text-accent-primary bg-accent-primary/10', icon: Send },\n SENT: { label: 'Sent', color: 'text-success-500 bg-success-100', icon: CheckCircle2 },\n DELIVERED: { label: 'Delivered', color: 'text-success-500 bg-success-100', icon: CheckCircle2 },\n FAILED: { label: 'Failed', color: 'text-error-500 bg-error-100', icon: XCircle },\n BOUNCED: { label: 'Bounced', color: 'text-warning-500 bg-warning-100', icon: AlertCircle },\n REJECTED: { label: 'Rejected', color: 'text-error-500 bg-error-100', icon: XCircle },\n RATE_LIMITED: { label: 'Rate Limited', color: 'text-warning-500 bg-warning-100', icon: Clock },\n RETRYING: {\n label: 'Retrying',\n color: 'text-accent-primary bg-accent-primary/10',\n icon: RefreshCw,\n },\n OPENED: { label: 'Opened', color: 'text-success-500 bg-success-100', icon: CheckCircle2 },\n CLICKED: { label: 'Clicked', color: 'text-success-500 bg-success-100', icon: CheckCircle2 },\n};\n\nexport function DeliveryHistoryPage() {\n const { channelId } = useParams<{ channelId: string }>();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { organizationId } = useChannelContext();\n const {\n triggerExport: exportDeliveries,\n isExporting: isExportingDeliveries,\n exportError: exportDeliveriesError,\n } = useExportDeliveryAttempts(organizationId ?? undefined, channelId);\n const [isLoadingAttempts, setIsLoadingAttempts] = useState(true);\n const [attempts, setAttempts] = useState<DeliveryAttempt[]>([]);\n const [retryingId, setRetryingId] = useState<string | null>(null);\n const [retryError, setRetryError] = useState<string | null>(null);\n const [limit, setLimit] = useState(25);\n\n const { channel, isLoading, error, fetchDeliveryAttempts, retryDelivery } = useChannel(channelId);\n\n const loadAttempts = useCallback(async () => {\n if (!channelId) return;\n setIsLoadingAttempts(true);\n setRetryError(null);\n try {\n const data = await fetchDeliveryAttempts(limit);\n setAttempts(data);\n } finally {\n setIsLoadingAttempts(false);\n }\n }, [channelId, fetchDeliveryAttempts, limit]);\n\n useEffect(() => {\n void Promise.resolve().then(() => loadAttempts());\n }, [loadAttempts]);\n\n // Real-time updates: subscribe to deliveryUpdated; if absent on the gateway,\n // the hook falls back to polling at 60s. Conservative fallback keeps cost\n // low when subs are unavailable. See useChannelSubscription.\n useChannelSubscription({\n query: DELIVERY_UPDATED_SUBSCRIPTION,\n variables: { channelId },\n operationName: 'DeliveryUpdated',\n enabled: Boolean(channelId),\n onData: () => void loadAttempts(),\n pollFn: loadAttempts,\n pollIntervalMs: 60_000,\n });\n\n const handleRetry = async (attemptId: string) => {\n setRetryingId(attemptId);\n setRetryError(null);\n try {\n const result = await retryDelivery(attemptId);\n if (!result.success) {\n setRetryError(result.error || 'Retry failed');\n }\n } finally {\n setRetryingId(null);\n }\n };\n\n const getStatusConfig = (status: DeliveryStatus) => {\n return STATUS_CONFIG[status] || STATUS_CONFIG.PENDING;\n };\n\n // Loading state\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 size={32} className=\"animate-spin text-accent-primary\" />\n </div>\n );\n }\n\n // Error state\n if (error || !channel) {\n return (\n <div className=\"p-6\">\n <div className=\"flex items-center gap-3 p-4 bg-error-100 border border-error-500 rounded-lg\">\n <AlertCircle size={20} className=\"text-error-500\" />\n <div>\n <p className=\"text-sm font-medium text-error-700\">{error || 'Channel not found'}</p>\n </div>\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"ml-auto px-3 py-1 text-sm text-error-700 hover:bg-error-200 rounded transition-colors\"\n >\n Go Back\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_DELIVERY_READ}>\n <div className=\"space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft size={20} />\n </button>\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tr('channel.deliveryHistory', 'Delivery History')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {channel.name} - Message deliveries\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <select\n value={limit}\n onChange={(e) => setLimit(Number(e.target.value))}\n className=\"px-3 py-2 text-sm bg-surface border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-bg/50 text-foreground\"\n >\n <option value={10}>10 results</option>\n <option value={25}>25 results</option>\n <option value={50}>50 results</option>\n <option value={100}>100 results</option>\n </select>\n <button\n onClick={loadAttempts}\n disabled={isLoadingAttempts}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50\"\n >\n <RefreshCw size={16} className={isLoadingAttempts ? 'animate-spin' : ''} />\n {tr('channel.refresh', 'Refresh')}\n </button>\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_ADMIN}>\n <button\n onClick={() => void exportDeliveries()}\n disabled={isExportingDeliveries}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-fg border border-border hover:bg-bg-elevated rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tr('channel.exportCSV', 'Export to CSV')}\n >\n {isExportingDeliveries ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Download size={16} />\n )}\n {tr('channel.export', 'Export')}\n </button>\n </PermissionGuard>\n </div>\n </div>\n\n {/* Export Error Banner */}\n {exportDeliveriesError && (\n <div className=\"p-4 bg-error-100 border border-error-500 rounded-lg flex items-center gap-3\">\n <AlertCircle size={20} className=\"text-error-500\" />\n <p className=\"text-sm text-error-700 flex-1\">{exportDeliveriesError}</p>\n </div>\n )}\n\n {/* Error Banner */}\n {retryError && (\n <div className=\"p-4 bg-error-100 border border-error-500 rounded-lg flex items-center gap-3\">\n <AlertCircle size={20} className=\"text-error-500\" />\n <p className=\"text-sm text-error-700 flex-1\">{retryError}</p>\n <button\n onClick={() => setRetryError(null)}\n className=\"text-error-500 hover:text-error-700\"\n >\n {tr('channel.dismiss', 'Dismiss')}\n </button>\n </div>\n )}\n\n {/* Info Banner */}\n <div className=\"p-4 bg-surface border border-border rounded-lg\">\n <p className=\"text-sm text-muted-foreground\">\n Delivery history shows all message attempts sent through this channel. Data is retained\n for 7 days. Click retry on a failed delivery to attempt sending again.\n </p>\n </div>\n\n {/* Deliveries List */}\n <div className=\"bg-surface border border-border rounded-lg overflow-hidden\">\n <div className=\"overflow-x-auto min-w-full\">\n <table className=\"w-full min-w-[700px]\">\n <thead className=\"bg-muted/50 border-b border-border\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.status', 'Status')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.content', 'Content')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.sentAt', 'Sent At')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.retries', 'Retries')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.error', 'Error')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {isLoadingAttempts ? (\n <tr>\n <td colSpan={6} className=\"px-4 py-12 text-center\">\n <Loader2 size={24} className=\"animate-spin text-accent-primary mx-auto\" />\n <p className=\"text-sm text-muted-foreground mt-2\">\n Loading delivery attempts...\n </p>\n </td>\n </tr>\n ) : attempts.length === 0 ? (\n <tr>\n <td colSpan={6} className=\"px-4 py-12 text-center\">\n <div className=\"flex flex-col items-center gap-2\">\n <Send size={32} className=\"text-muted-foreground\" />\n <p className=\"text-sm font-medium text-foreground\">\n {tr('channel.noDeliveryAttempts', 'No delivery attempts yet')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n 'channel.sendMessageToSeeHistory',\n 'Send a message through this channel to see delivery history'\n )}\n </p>\n </div>\n </td>\n </tr>\n ) : (\n attempts.map((delivery) => {\n const statusConfig = getStatusConfig(delivery.status as DeliveryStatus);\n const StatusIcon = statusConfig.icon;\n const canRetry =\n delivery.status === 'FAILED' ||\n delivery.status === 'BOUNCED' ||\n delivery.status === 'REJECTED';\n return (\n <tr key={delivery.id} className=\"hover:bg-muted/30 transition-colors\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <StatusIcon size={14} className={statusConfig.color.split(' ')[0]} />\n <span className={`text-sm font-medium ${statusConfig.color}`}>\n {statusConfig.label}\n </span>\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm text-foreground truncate max-w-xs\">\n {delivery.content}\n </td>\n <td className=\"px-4 py-3 text-sm text-muted-foreground\">\n {delivery.sentAt ? new Date(delivery.sentAt).toLocaleString() : '-'}\n </td>\n <td className=\"px-4 py-3 text-sm text-muted-foreground\">\n {delivery.retryCount}\n </td>\n <td className=\"px-4 py-3 text-sm text-error-500 max-w-xs truncate\">\n {delivery.errorMessage || '-'}\n </td>\n <td className=\"px-4 py-3\">\n {canRetry && (\n <PermissionGuard\n permission={CHANNEL_PERMISSIONS.CHANNEL_DELIVERY_EXECUTE}\n >\n <button\n onClick={() => handleRetry(delivery.id)}\n disabled={retryingId === delivery.id}\n className=\"flex items-center gap-1 px-2 py-1 text-xs font-medium text-accent-primary hover:bg-accent-primary/10 rounded transition-colors disabled:opacity-50\"\n title={tr('channel.retryDelivery', 'Retry this delivery')}\n >\n <RotateCcw\n size={12}\n className={retryingId === delivery.id ? 'animate-spin' : ''}\n />\n {retryingId === delivery.id\n ? tr('channel.retrying', 'Retrying...')\n : tr('channel.retry', 'Retry')}\n </button>\n </PermissionGuard>\n )}\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Edit Channel Page
3
+ *
4
+ * Allows editing an existing channel's configuration.
5
+ * Uses the same form structure as CreateChannelPage but pre-fills existing values.
6
+ */
7
+ export declare function EditChannelPage(): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=EditChannelPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditChannelPage.d.ts","sourceRoot":"","sources":["../../../../../src/channel/modules/channels/pages/EditChannelPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiKH,wBAAgB,eAAe,4CAkV9B"}
@@ -0,0 +1,459 @@
1
+ import { nativeImpact as e, nativeNotify as t } from "../../../../utils/nativeBridge.js";
2
+ import { useChannel as n, useChannels as r } from "../../../hooks/useChannels.js";
3
+ import { PermissionGuard as i } from "../../../components/PermissionGuard.js";
4
+ import { CHANNEL_PERMISSIONS as a } from "../../../constants/permissions.js";
5
+ import { useEffect as o, useRef as s, useState as c } from "react";
6
+ import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
+ import { AlertCircle as u, ArrowLeft as d, Bell as f, Hash as p, Inbox as m, Loader2 as h, Mail as g, MessageCircle as _, MessageSquare as v, Save as y, Send as b, Smartphone as x, Trash2 as S, Users as C } from "lucide-react";
8
+ import { useNavigate as w, useParams as T } from "react-router-dom";
9
+ import { Fragment as E, jsx as D, jsxs as O } from "react/jsx-runtime";
10
+ //#region src/channel/modules/channels/pages/EditChannelPage.tsx
11
+ var k = [
12
+ {
13
+ value: "EMAIL",
14
+ label: "Email",
15
+ description: "Send emails via various providers",
16
+ icon: g,
17
+ color: "text-blue-400 bg-blue-500/15 border-blue-500/30",
18
+ adapters: [
19
+ {
20
+ value: "AWS_SES",
21
+ label: "AWS SES"
22
+ },
23
+ {
24
+ value: "MAILGUN",
25
+ label: "Mailgun"
26
+ },
27
+ {
28
+ value: "POSTMARK",
29
+ label: "Postmark"
30
+ },
31
+ {
32
+ value: "MANDRILL",
33
+ label: "Mandrill"
34
+ },
35
+ {
36
+ value: "RESEND",
37
+ label: "Resend"
38
+ },
39
+ {
40
+ value: "AZURE_ACS",
41
+ label: "Azure Communication Services"
42
+ },
43
+ {
44
+ value: "SMTP",
45
+ label: "Custom SMTP"
46
+ }
47
+ ]
48
+ },
49
+ {
50
+ value: "SMS",
51
+ label: "SMS",
52
+ description: "Send text messages",
53
+ icon: x,
54
+ color: "text-green-400 bg-green-500/15 border-green-500/30",
55
+ adapters: [
56
+ {
57
+ value: "TWILIO_SMS",
58
+ label: "Twilio"
59
+ },
60
+ {
61
+ value: "AWS_SNS",
62
+ label: "AWS SNS"
63
+ },
64
+ {
65
+ value: "VONAGE",
66
+ label: "Vonage"
67
+ },
68
+ {
69
+ value: "PLIVO",
70
+ label: "Plivo"
71
+ },
72
+ {
73
+ value: "MESSAGEBIRD",
74
+ label: "MessageBird"
75
+ },
76
+ {
77
+ value: "INFOBIP",
78
+ label: "Infobip"
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ value: "PUSH",
84
+ label: "Push",
85
+ description: "Mobile & web push",
86
+ icon: f,
87
+ color: "text-purple-400 bg-purple-500/15 border-purple-500/30",
88
+ adapters: [
89
+ {
90
+ value: "FCM",
91
+ label: "Firebase Cloud Messaging"
92
+ },
93
+ {
94
+ value: "APNS",
95
+ label: "Apple Push Notification Service"
96
+ },
97
+ {
98
+ value: "ONESIGNAL",
99
+ label: "OneSignal"
100
+ },
101
+ {
102
+ value: "EXPO",
103
+ label: "Expo Push"
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ value: "INAPP",
109
+ label: "In-App",
110
+ description: "Internal in-app notifications",
111
+ icon: m,
112
+ color: "text-orange-400 bg-orange-500/15 border-orange-500/30",
113
+ adapters: [{
114
+ value: "INAPP_NATIVE",
115
+ label: "Native In-App"
116
+ }]
117
+ },
118
+ {
119
+ value: "WHATSAPP",
120
+ label: "WhatsApp",
121
+ description: "WhatsApp Business messaging",
122
+ icon: v,
123
+ color: "text-green-500 bg-green-500/15 border-green-500/30",
124
+ adapters: [{
125
+ value: "WHATSAPP_CLOUD",
126
+ label: "WhatsApp Cloud API"
127
+ }, {
128
+ value: "WHATSAPP_TWILIO",
129
+ label: "WhatsApp via Twilio"
130
+ }]
131
+ },
132
+ {
133
+ value: "SLACK",
134
+ label: "Slack",
135
+ description: "Slack bot & channels",
136
+ icon: p,
137
+ color: "text-pink-400 bg-pink-500/15 border-pink-500/30",
138
+ adapters: [{
139
+ value: "SLACK_BOT",
140
+ label: "Slack Bot"
141
+ }]
142
+ },
143
+ {
144
+ value: "TEAMS",
145
+ label: "Teams",
146
+ description: "Microsoft Teams",
147
+ icon: C,
148
+ color: "text-blue-400 bg-blue-500/15 border-blue-500/30",
149
+ adapters: [{
150
+ value: "TEAMS_BOT",
151
+ label: "Teams Bot"
152
+ }]
153
+ },
154
+ {
155
+ value: "DISCORD",
156
+ label: "Discord",
157
+ description: "Discord bots & webhooks",
158
+ icon: _,
159
+ color: "text-indigo-400 bg-indigo-500/15 border-indigo-500/30",
160
+ adapters: [{
161
+ value: "DISCORD_BOT",
162
+ label: "Discord Bot"
163
+ }]
164
+ },
165
+ {
166
+ value: "WEBCHAT",
167
+ label: "Webchat",
168
+ description: "Website live chat",
169
+ icon: v,
170
+ color: "text-cyan-400 bg-cyan-500/15 border-cyan-500/30",
171
+ adapters: [{
172
+ value: "WEBCHAT_NATIVE",
173
+ label: "Native Webchat"
174
+ }]
175
+ },
176
+ {
177
+ value: "WEBHOOK",
178
+ label: "Webhook",
179
+ description: "Generic HTTP webhook",
180
+ icon: b,
181
+ color: "text-gray-400 bg-gray-500/15 border-gray-500/30",
182
+ adapters: [{
183
+ value: "WEBHOOK_HTTP",
184
+ label: "HTTP Webhook"
185
+ }]
186
+ }
187
+ ], A = [
188
+ {
189
+ value: 0,
190
+ label: "0 - Lowest"
191
+ },
192
+ {
193
+ value: 1,
194
+ label: "1 - Low"
195
+ },
196
+ {
197
+ value: 2,
198
+ label: "2 - Normal"
199
+ },
200
+ {
201
+ value: 3,
202
+ label: "3 - High"
203
+ },
204
+ {
205
+ value: 4,
206
+ label: "4 - Highest"
207
+ }
208
+ ];
209
+ function j() {
210
+ let f = w(), { channelId: p } = T(), { channel: m, isLoading: g, error: _ } = n(p), { updateChannel: v, deleteChannel: b } = r(), { t: x } = l(), C = (e, t) => {
211
+ let n = x(e);
212
+ return n === e ? t : n;
213
+ }, [j, M] = c(""), [N, P] = c(""), [F, I] = c("AWS_SES"), [L, R] = c(2), [z, B] = c("INACTIVE"), [V, H] = c(!1), [U, W] = c(!1), [G, K] = c(null), [q, J] = c(!1), Y = s(null);
214
+ o(() => {
215
+ m && m.id !== Y.current && (Y.current = m.id, Promise.resolve().then(() => {
216
+ M(m.name || ""), P(m.description || ""), I(m.adapterType || "AWS_SES"), R(m.priority || 2), B(m.status || "INACTIVE");
217
+ }));
218
+ }, [m]);
219
+ let X = m?.platform || "EMAIL", Z = k.find((e) => e.value === X);
220
+ return g ? /* @__PURE__ */ D("div", {
221
+ className: "flex items-center justify-center min-h-screen",
222
+ children: /* @__PURE__ */ D(h, { className: "w-8 h-8 animate-spin text-muted-foreground" })
223
+ }) : _ || !m ? /* @__PURE__ */ O("div", {
224
+ className: "flex flex-col items-center justify-center min-h-screen gap-4",
225
+ children: [
226
+ /* @__PURE__ */ D(u, { className: "w-12 h-12 text-destructive" }),
227
+ /* @__PURE__ */ D("h1", {
228
+ className: "text-xl font-semibold",
229
+ children: C("channel.channelNotFound", "Channel not found")
230
+ }),
231
+ /* @__PURE__ */ D("button", {
232
+ onClick: () => f("../list"),
233
+ className: "text-primary hover:underline",
234
+ children: C("channel.backToChannels", "Back to channels")
235
+ })
236
+ ]
237
+ }) : /* @__PURE__ */ D(i, {
238
+ permission: a.CHANNEL_UPDATE,
239
+ children: /* @__PURE__ */ O("div", {
240
+ className: "min-h-screen bg-background",
241
+ children: [/* @__PURE__ */ D("div", {
242
+ className: "border-b bg-card",
243
+ children: /* @__PURE__ */ D("div", {
244
+ className: "container mx-auto px-6 py-4",
245
+ children: /* @__PURE__ */ O("div", {
246
+ className: "flex items-center gap-4",
247
+ children: [/* @__PURE__ */ D("button", {
248
+ onClick: () => f(`/channels/${p}`),
249
+ className: "p-2 hover:bg-muted rounded-lg transition-colors",
250
+ children: /* @__PURE__ */ D(d, { className: "w-5 h-5" })
251
+ }), /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("h1", {
252
+ className: "text-2xl font-bold",
253
+ children: C("channel.editChannel", "Edit Channel")
254
+ }), /* @__PURE__ */ D("p", {
255
+ className: "text-sm text-muted-foreground",
256
+ children: C("channel.updateChannelConfig", "Update channel configuration")
257
+ })] })]
258
+ })
259
+ })
260
+ }), /* @__PURE__ */ D("div", {
261
+ className: "container mx-auto px-6 py-8 max-w-2xl",
262
+ children: /* @__PURE__ */ O("div", {
263
+ className: "space-y-6",
264
+ children: [
265
+ G && /* @__PURE__ */ O("div", {
266
+ className: "p-4 rounded-lg bg-destructive/10 border border-destructive/20 flex items-center gap-3",
267
+ children: [/* @__PURE__ */ D(u, { className: "w-5 h-5 text-destructive shrink-0" }), /* @__PURE__ */ D("p", {
268
+ className: "text-sm text-destructive",
269
+ children: G
270
+ })]
271
+ }),
272
+ /* @__PURE__ */ O("div", {
273
+ className: "p-4 rounded-lg bg-muted/50 border space-y-2",
274
+ children: [/* @__PURE__ */ D("div", {
275
+ className: "flex items-center gap-2",
276
+ children: Z && /* @__PURE__ */ O(E, { children: [(() => {
277
+ let e = Z.icon;
278
+ return /* @__PURE__ */ D(e, { className: "w-5 h-5 text-muted-foreground" });
279
+ })(), /* @__PURE__ */ D("span", {
280
+ className: "font-medium",
281
+ children: X
282
+ })] })
283
+ }), /* @__PURE__ */ D("p", {
284
+ className: "text-sm text-muted-foreground",
285
+ children: C("channel.platformLockedHint", "Platform cannot be changed after channel creation. Create a new channel to use a different platform.")
286
+ })]
287
+ }),
288
+ /* @__PURE__ */ O("div", {
289
+ className: "space-y-2",
290
+ children: [/* @__PURE__ */ O("label", {
291
+ className: "text-sm font-medium",
292
+ children: [C("channel.channelName", "Channel Name"), " *"]
293
+ }), /* @__PURE__ */ D("input", {
294
+ type: "text",
295
+ value: j,
296
+ onChange: (e) => M(e.target.value),
297
+ placeholder: C("channel.editNamePlaceholder", "e.g., Production Email, Customer SMS"),
298
+ className: "w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary"
299
+ })]
300
+ }),
301
+ /* @__PURE__ */ O("div", {
302
+ className: "space-y-2",
303
+ children: [/* @__PURE__ */ D("label", {
304
+ className: "text-sm font-medium",
305
+ children: C("channel.description", "Description")
306
+ }), /* @__PURE__ */ D("textarea", {
307
+ value: N,
308
+ onChange: (e) => P(e.target.value),
309
+ placeholder: C("channel.editDescriptionPlaceholder", "Optional description for this channel"),
310
+ rows: 3,
311
+ className: "w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary resize-none"
312
+ })]
313
+ }),
314
+ Z && /* @__PURE__ */ O("div", {
315
+ className: "space-y-2",
316
+ children: [/* @__PURE__ */ D("label", {
317
+ className: "text-sm font-medium",
318
+ children: C("channel.adapterProvider", "Adapter / Provider")
319
+ }), /* @__PURE__ */ D("select", {
320
+ value: F,
321
+ onChange: (e) => I(e.target.value),
322
+ className: "w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary",
323
+ children: Z.adapters.map((e) => /* @__PURE__ */ D("option", {
324
+ value: e.value,
325
+ children: e.label
326
+ }, e.value))
327
+ })]
328
+ }),
329
+ /* @__PURE__ */ O("div", {
330
+ className: "grid grid-cols-2 gap-4",
331
+ children: [/* @__PURE__ */ O("div", {
332
+ className: "space-y-2",
333
+ children: [
334
+ /* @__PURE__ */ D("label", {
335
+ className: "text-sm font-medium",
336
+ children: C("channel.priority", "Priority")
337
+ }),
338
+ /* @__PURE__ */ D("select", {
339
+ value: L,
340
+ onChange: (e) => R(Number(e.target.value)),
341
+ className: "w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary",
342
+ children: A.map((e) => /* @__PURE__ */ D("option", {
343
+ value: e.value,
344
+ children: e.label
345
+ }, e.value))
346
+ }),
347
+ /* @__PURE__ */ D("p", {
348
+ className: "text-xs text-muted-foreground",
349
+ children: C("channel.priorityFailoverHint", "Higher priority channels are used first in failover")
350
+ })
351
+ ]
352
+ }), /* @__PURE__ */ O("div", {
353
+ className: "space-y-2",
354
+ children: [/* @__PURE__ */ D("label", {
355
+ className: "text-sm font-medium",
356
+ children: C("channel.status", "Status")
357
+ }), /* @__PURE__ */ O("select", {
358
+ value: z,
359
+ onChange: (e) => B(e.target.value),
360
+ className: "w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary",
361
+ children: [
362
+ /* @__PURE__ */ D("option", {
363
+ value: "INACTIVE",
364
+ children: C("channel.status.inactive", "Inactive")
365
+ }),
366
+ /* @__PURE__ */ D("option", {
367
+ value: "ACTIVE",
368
+ children: C("channel.status.active", "Active")
369
+ }),
370
+ /* @__PURE__ */ D("option", {
371
+ value: "SUSPENDED",
372
+ children: C("channel.status.suspended", "Suspended")
373
+ })
374
+ ]
375
+ })]
376
+ })]
377
+ }),
378
+ /* @__PURE__ */ O("div", {
379
+ className: "flex items-center justify-between pt-6 border-t",
380
+ children: [/* @__PURE__ */ D("div", { children: q ? /* @__PURE__ */ O("div", {
381
+ className: "flex items-center gap-2",
382
+ children: [
383
+ /* @__PURE__ */ D("span", {
384
+ className: "text-sm text-muted-foreground",
385
+ children: C("channel.confirmDelete", "Confirm delete?")
386
+ }),
387
+ /* @__PURE__ */ O("button", {
388
+ onClick: async () => {
389
+ if (!(!p || !q)) {
390
+ e("medium"), W(!0);
391
+ try {
392
+ await b(p) ? (t("success"), f("../list")) : t("error");
393
+ } catch (e) {
394
+ t("error"), K(e instanceof Error ? e.message : C("channel.deleteFailed", "Failed to delete channel")), W(!1);
395
+ }
396
+ }
397
+ },
398
+ disabled: U,
399
+ className: "px-4 py-2 text-sm bg-destructive text-destructive-foreground rounded-lg hover:bg-destructive/90 transition-colors flex items-center gap-2",
400
+ children: [U ? /* @__PURE__ */ D(h, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ D(S, { className: "w-4 h-4" }), C("channel.delete", "Delete")]
401
+ }),
402
+ /* @__PURE__ */ D("button", {
403
+ onClick: () => J(!1),
404
+ className: "px-4 py-2 text-sm text-muted-foreground hover:bg-muted rounded-lg transition-colors",
405
+ children: C("channel.cancel", "Cancel")
406
+ })
407
+ ]
408
+ }) : /* @__PURE__ */ D(i, {
409
+ permission: a.CHANNEL_DELETE,
410
+ children: /* @__PURE__ */ O("button", {
411
+ onClick: () => J(!0),
412
+ className: "px-4 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors flex items-center gap-2",
413
+ children: [/* @__PURE__ */ D(S, { className: "w-4 h-4" }), C("channel.deleteChannel", "Delete Channel")]
414
+ })
415
+ }) }), /* @__PURE__ */ O("div", {
416
+ className: "flex items-center gap-3",
417
+ children: [/* @__PURE__ */ D("button", {
418
+ onClick: () => f(`/channels/${p}`),
419
+ className: "px-4 py-2 text-sm text-muted-foreground hover:bg-muted rounded-lg transition-colors",
420
+ children: C("channel.cancel", "Cancel")
421
+ }), /* @__PURE__ */ O("button", {
422
+ onClick: async () => {
423
+ if (p) {
424
+ if (!j.trim()) {
425
+ K(C("channel.validation.nameRequired", "Channel name is required"));
426
+ return;
427
+ }
428
+ H(!0), K(null);
429
+ try {
430
+ await v(p, {
431
+ name: j.trim(),
432
+ description: N.trim() || void 0,
433
+ adapterType: F,
434
+ priority: L,
435
+ status: z
436
+ }) ? f(`/channels/${p}`) : K(C("channel.updateFailed", "Failed to update channel"));
437
+ } catch (e) {
438
+ K(e instanceof Error ? e.message : C("channel.updateFailed", "Failed to update channel"));
439
+ } finally {
440
+ H(!1);
441
+ }
442
+ }
443
+ },
444
+ disabled: V || !j.trim(),
445
+ className: "px-6 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors flex items-center gap-2 disabled:opacity-50",
446
+ children: [V ? /* @__PURE__ */ D(h, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ D(y, { className: "w-4 h-4" }), C("channel.saveChanges", "Save Changes")]
447
+ })]
448
+ })]
449
+ })
450
+ ]
451
+ })
452
+ })]
453
+ })
454
+ });
455
+ }
456
+ //#endregion
457
+ export { j as EditChannelPage };
458
+
459
+ //# sourceMappingURL=EditChannelPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditChannelPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/EditChannelPage.tsx"],"sourcesContent":["/**\n * Edit Channel Page\n *\n * Allows editing an existing channel's configuration.\n * Uses the same form structure as CreateChannelPage but pre-fills existing values.\n */\n\nimport { useState, useEffect, useRef } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ArrowLeft,\n Save,\n Loader2,\n AlertCircle,\n Mail,\n Smartphone,\n Bell,\n Inbox,\n MessageSquare,\n Hash,\n Users,\n MessageCircle,\n Send,\n Trash2,\n} from 'lucide-react';\nimport { useChannel, useChannels } from '../../../hooks/useChannels';\nimport {\n type ChannelPlatform,\n type AdapterType,\n type ChannelStatus,\n type UpdateChannelInput,\n} from '../../../hooks/useChannels';\nimport { nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\n\n// ============================================================================\n// PLATFORM CONFIG (same as CreateChannelPage)\n// ============================================================================\n\nconst PLATFORM_OPTIONS: {\n value: ChannelPlatform;\n label: string;\n description: string;\n icon: typeof Mail;\n color: string;\n adapters: { value: AdapterType; label: string }[];\n}[] = [\n {\n value: 'EMAIL',\n label: 'Email',\n description: 'Send emails via various providers',\n icon: Mail,\n color: 'text-blue-400 bg-blue-500/15 border-blue-500/30',\n adapters: [\n { value: 'AWS_SES', label: 'AWS SES' },\n { value: 'MAILGUN', label: 'Mailgun' },\n { value: 'POSTMARK', label: 'Postmark' },\n { value: 'MANDRILL', label: 'Mandrill' },\n { value: 'RESEND', label: 'Resend' },\n { value: 'AZURE_ACS', label: 'Azure Communication Services' },\n { value: 'SMTP', label: 'Custom SMTP' },\n ],\n },\n {\n value: 'SMS',\n label: 'SMS',\n description: 'Send text messages',\n icon: Smartphone,\n color: 'text-green-400 bg-green-500/15 border-green-500/30',\n adapters: [\n { value: 'TWILIO_SMS', label: 'Twilio' },\n { value: 'AWS_SNS', label: 'AWS SNS' },\n { value: 'VONAGE', label: 'Vonage' },\n { value: 'PLIVO', label: 'Plivo' },\n { value: 'MESSAGEBIRD', label: 'MessageBird' },\n { value: 'INFOBIP', label: 'Infobip' },\n ],\n },\n {\n value: 'PUSH',\n label: 'Push',\n description: 'Mobile & web push',\n icon: Bell,\n color: 'text-purple-400 bg-purple-500/15 border-purple-500/30',\n adapters: [\n { value: 'FCM', label: 'Firebase Cloud Messaging' },\n { value: 'APNS', label: 'Apple Push Notification Service' },\n { value: 'ONESIGNAL', label: 'OneSignal' },\n { value: 'EXPO', label: 'Expo Push' },\n ],\n },\n {\n value: 'INAPP',\n label: 'In-App',\n description: 'Internal in-app notifications',\n icon: Inbox,\n color: 'text-orange-400 bg-orange-500/15 border-orange-500/30',\n adapters: [{ value: 'INAPP_NATIVE', label: 'Native In-App' }],\n },\n {\n value: 'WHATSAPP',\n label: 'WhatsApp',\n description: 'WhatsApp Business messaging',\n icon: MessageSquare,\n color: 'text-green-500 bg-green-500/15 border-green-500/30',\n adapters: [\n { value: 'WHATSAPP_CLOUD', label: 'WhatsApp Cloud API' },\n { value: 'WHATSAPP_TWILIO', label: 'WhatsApp via Twilio' },\n ],\n },\n {\n value: 'SLACK',\n label: 'Slack',\n description: 'Slack bot & channels',\n icon: Hash,\n color: 'text-pink-400 bg-pink-500/15 border-pink-500/30',\n adapters: [{ value: 'SLACK_BOT', label: 'Slack Bot' }],\n },\n {\n value: 'TEAMS',\n label: 'Teams',\n description: 'Microsoft Teams',\n icon: Users,\n color: 'text-blue-400 bg-blue-500/15 border-blue-500/30',\n adapters: [{ value: 'TEAMS_BOT', label: 'Teams Bot' }],\n },\n {\n value: 'DISCORD',\n label: 'Discord',\n description: 'Discord bots & webhooks',\n icon: MessageCircle,\n color: 'text-indigo-400 bg-indigo-500/15 border-indigo-500/30',\n adapters: [{ value: 'DISCORD_BOT', label: 'Discord Bot' }],\n },\n {\n value: 'WEBCHAT',\n label: 'Webchat',\n description: 'Website live chat',\n icon: MessageSquare,\n color: 'text-cyan-400 bg-cyan-500/15 border-cyan-500/30',\n adapters: [{ value: 'WEBCHAT_NATIVE', label: 'Native Webchat' }],\n },\n {\n value: 'WEBHOOK',\n label: 'Webhook',\n description: 'Generic HTTP webhook',\n icon: Send,\n color: 'text-gray-400 bg-gray-500/15 border-gray-500/30',\n adapters: [{ value: 'WEBHOOK_HTTP', label: 'HTTP Webhook' }],\n },\n];\n\nconst PRIORITY_OPTIONS = [\n { value: 0, label: '0 - Lowest' },\n { value: 1, label: '1 - Low' },\n { value: 2, label: '2 - Normal' },\n { value: 3, label: '3 - High' },\n { value: 4, label: '4 - Highest' },\n];\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport function EditChannelPage() {\n const navigate = useNavigate();\n const { channelId } = useParams<{ channelId: string }>();\n const { channel, isLoading, error } = useChannel(channelId!);\n const { updateChannel, deleteChannel } = useChannels();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n // Form state\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [adapterType, setAdapterType] = useState<AdapterType>('AWS_SES');\n const [priority, setPriority] = useState(2);\n const [status, setStatus] = useState<ChannelStatus>('INACTIVE');\n\n // UI state\n const [isSaving, setIsSaving] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [deleteConfirm, setDeleteConfirm] = useState(false);\n\n // Load channel data into form — guard against re-initialization and defer\n // the state update to a microtask so setState does not run synchronously\n // inside the effect body (react-hooks/set-state-in-effect).\n const loadedChannelIdRef = useRef<string | null>(null);\n useEffect(() => {\n if (channel && channel.id !== loadedChannelIdRef.current) {\n loadedChannelIdRef.current = channel.id;\n void Promise.resolve().then(() => {\n setName(channel.name || '');\n setDescription(channel.description || '');\n setAdapterType((channel.adapterType || 'AWS_SES') as AdapterType);\n setPriority(channel.priority || 2);\n setStatus((channel.status || 'INACTIVE') as ChannelStatus);\n });\n }\n }, [channel]);\n\n // Update adapter options when platform changes\n const currentPlatform = (channel?.platform || 'EMAIL') as ChannelPlatform;\n const selectedPlatform = PLATFORM_OPTIONS.find((p) => p.value === currentPlatform);\n\n const handleSave = async () => {\n if (!channelId) return;\n\n if (!name.trim()) {\n setSaveError(tr('channel.validation.nameRequired', 'Channel name is required'));\n return;\n }\n\n setIsSaving(true);\n setSaveError(null);\n\n try {\n const input: UpdateChannelInput = {\n name: name.trim(),\n description: description.trim() || undefined,\n adapterType,\n priority,\n status,\n };\n\n const result = await updateChannel(channelId, input);\n if (result) {\n navigate(`/channels/${channelId}`);\n } else {\n setSaveError(tr('channel.updateFailed', 'Failed to update channel'));\n }\n } catch (err: unknown) {\n const message =\n err instanceof Error ? err.message : tr('channel.updateFailed', 'Failed to update channel');\n setSaveError(message);\n } finally {\n setIsSaving(false);\n }\n };\n\n const handleDelete = async () => {\n if (!channelId || !deleteConfirm) return;\n void nativeImpact('medium');\n\n setIsDeleting(true);\n try {\n const success = await deleteChannel(channelId);\n if (success) {\n void nativeNotify('success');\n navigate('../list');\n } else {\n void nativeNotify('error');\n }\n } catch (err: unknown) {\n void nativeNotify('error');\n const message =\n err instanceof Error ? err.message : tr('channel.deleteFailed', 'Failed to delete channel');\n setSaveError(message);\n setIsDeleting(false);\n }\n };\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"w-8 h-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error || !channel) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"w-12 h-12 text-destructive\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.channelNotFound', 'Channel not found')}\n </h1>\n <button onClick={() => navigate('../list')} className=\"text-primary hover:underline\">\n {tr('channel.backToChannels', 'Back to channels')}\n </button>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_UPDATE}>\n <div className=\"min-h-screen bg-background\">\n {/* Header */}\n <div className=\"border-b bg-card\">\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center gap-4\">\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"w-5 h-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">{tr('channel.editChannel', 'Edit Channel')}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {tr('channel.updateChannelConfig', 'Update channel configuration')}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n {/* Form */}\n <div className=\"container mx-auto px-6 py-8 max-w-2xl\">\n <div className=\"space-y-6\">\n {/* Error Alert */}\n {saveError && (\n <div className=\"p-4 rounded-lg bg-destructive/10 border border-destructive/20 flex items-center gap-3\">\n <AlertCircle className=\"w-5 h-5 text-destructive shrink-0\" />\n <p className=\"text-sm text-destructive\">{saveError}</p>\n </div>\n )}\n\n {/* Channel Info (read-only) */}\n <div className=\"p-4 rounded-lg bg-muted/50 border space-y-2\">\n <div className=\"flex items-center gap-2\">\n {selectedPlatform && (\n <>\n {(() => {\n const Icon = selectedPlatform.icon;\n return <Icon className=\"w-5 h-5 text-muted-foreground\" />;\n })()}\n <span className=\"font-medium\">{currentPlatform}</span>\n </>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'channel.platformLockedHint',\n 'Platform cannot be changed after channel creation. Create a new channel to use a different platform.'\n )}\n </p>\n </div>\n\n {/* Name */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {tr('channel.channelName', 'Channel Name')} *\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={tr(\n 'channel.editNamePlaceholder',\n 'e.g., Production Email, Customer SMS'\n )}\n className=\"w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n\n {/* Description */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {tr('channel.description', 'Description')}\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={tr(\n 'channel.editDescriptionPlaceholder',\n 'Optional description for this channel'\n )}\n rows={3}\n className=\"w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary resize-none\"\n />\n </div>\n\n {/* Adapter Type */}\n {selectedPlatform && (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {tr('channel.adapterProvider', 'Adapter / Provider')}\n </label>\n <select\n value={adapterType}\n onChange={(e) => setAdapterType(e.target.value as AdapterType)}\n className=\"w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n {selectedPlatform.adapters.map((adapter) => (\n <option key={adapter.value} value={adapter.value}>\n {adapter.label}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Priority & Status */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{tr('channel.priority', 'Priority')}</label>\n <select\n value={priority}\n onChange={(e) => setPriority(Number(e.target.value))}\n className=\"w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n {PRIORITY_OPTIONS.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n 'channel.priorityFailoverHint',\n 'Higher priority channels are used first in failover'\n )}\n </p>\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{tr('channel.status', 'Status')}</label>\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as ChannelStatus)}\n className=\"w-full px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"INACTIVE\">{tr('channel.status.inactive', 'Inactive')}</option>\n <option value=\"ACTIVE\">{tr('channel.status.active', 'Active')}</option>\n <option value=\"SUSPENDED\">{tr('channel.status.suspended', 'Suspended')}</option>\n </select>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-6 border-t\">\n {/* Delete */}\n <div>\n {!deleteConfirm ? (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_DELETE}>\n <button\n onClick={() => setDeleteConfirm(true)}\n className=\"px-4 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors flex items-center gap-2\"\n >\n <Trash2 className=\"w-4 h-4\" />\n {tr('channel.deleteChannel', 'Delete Channel')}\n </button>\n </PermissionGuard>\n ) : (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n {tr('channel.confirmDelete', 'Confirm delete?')}\n </span>\n <button\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"px-4 py-2 text-sm bg-destructive text-destructive-foreground rounded-lg hover:bg-destructive/90 transition-colors flex items-center gap-2\"\n >\n {isDeleting ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Trash2 className=\"w-4 h-4\" />\n )}\n {tr('channel.delete', 'Delete')}\n </button>\n <button\n onClick={() => setDeleteConfirm(false)}\n className=\"px-4 py-2 text-sm text-muted-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n {tr('channel.cancel', 'Cancel')}\n </button>\n </div>\n )}\n </div>\n\n {/* Save */}\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"px-4 py-2 text-sm text-muted-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n {tr('channel.cancel', 'Cancel')}\n </button>\n <button\n onClick={handleSave}\n disabled={isSaving || !name.trim()}\n className=\"px-6 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n {isSaving ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Save className=\"w-4 h-4\" />\n )}\n {tr('channel.saveChanges', 'Save Changes')}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Edit Connection Page
3
+ *
4
+ * Standalone page mounted at /channels/connections/:connectionId/edit.
5
+ * Fetches the connection directly via getConnection (no channelId required in URL).
6
+ *
7
+ * Form fields match UpdateConnectionInput exactly.
8
+ */
9
+ export declare function EditConnectionPage(): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=EditConnectionPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditConnectionPage.d.ts","sourceRoot":"","sources":["../../../../../src/channel/modules/channels/pages/EditConnectionPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAoBH,wBAAgB,kBAAkB,4CA6OjC"}