diff --git a/web/src/app/storybook/defaultDestTypes.ts b/web/src/app/storybook/defaultDestTypes.ts
index eca300d23f..6bcdbfe09e 100644
--- a/web/src/app/storybook/defaultDestTypes.ts
+++ b/web/src/app/storybook/defaultDestTypes.ts
@@ -165,4 +165,32 @@ export const destTypes: DestinationTypeInfo[] = [
},
],
},
+ {
+ type: 'webhook-field',
+ name: 'Webhook Field Destination Type',
+ enabled: true,
+ disabledMessage: 'Webhook field destination type must be configured.',
+ userDisclaimer: '',
+ isContactMethod: true,
+ isEPTarget: false,
+ isSchedOnCallNotify: false,
+ iconURL: '',
+ iconAltText: '',
+ supportsStatusUpdates: true,
+ statusUpdatesRequired: false,
+ requiredFields: [
+ {
+ fieldID: 'webhook-url',
+ labelSingular: 'Webhook Url',
+ labelPlural: '',
+ hint: 'Some hint text',
+ hintURL: '',
+ placeholderText: 'https://target.com',
+ prefix: '',
+ inputType: 'url',
+ isSearchSelectable: false,
+ supportsValidation: false,
+ },
+ ],
+ },
]
diff --git a/web/src/app/users/UserContactMethodListDest.stories.tsx b/web/src/app/users/UserContactMethodListDest.stories.tsx
new file mode 100644
index 0000000000..297cb3dd06
--- /dev/null
+++ b/web/src/app/users/UserContactMethodListDest.stories.tsx
@@ -0,0 +1,131 @@
+import React from 'react'
+import type { Meta, StoryObj } from '@storybook/react'
+import UserContactMethodListDest from './UserContactMethodListDest'
+import { expect, within } from '@storybook/test'
+import { handleDefaultConfig, handleExpFlags } from '../storybook/graphql'
+import { HttpResponse, graphql } from 'msw'
+
+const meta = {
+ title: 'users/UserContactMethodListDest',
+ component: UserContactMethodListDest,
+ tags: ['autodocs'],
+ parameters: {
+ msw: {
+ handlers: [
+ handleDefaultConfig,
+ handleExpFlags('dest-types'),
+ graphql.query('cmList', ({ variables: vars }) => {
+ return HttpResponse.json({
+ data:
+ vars.id === '00000000-0000-0000-0000-000000000001'
+ ? {
+ user: {
+ id: '00000000-0000-0000-0000-000000000001',
+ contactMethods: [
+ {
+ id: '12345',
+ name: 'Josiah',
+ dest: {
+ type: 'single-field',
+ values: [
+ {
+ fieldID: 'phone-number',
+ value: '+15555555555',
+ label: '+1 555-555-5555',
+ },
+ ],
+ },
+ disabled: false,
+ pending: false,
+ },
+ ],
+ },
+ }
+ : {
+ user: {
+ id: '00000000-0000-0000-0000-000000000002',
+ contactMethods: [
+ {
+ id: '67890',
+ name: 'triple contact method',
+ dest: {
+ type: 'triple-field',
+ values: [
+ {
+ fieldID: 'first-field',
+ value: '+15555555555',
+ label: '+1 555-555-5555',
+ },
+ {
+ fieldID: 'second-field',
+ value: 'test_user@target.com',
+ label: 'test_user@target.com',
+ },
+ {
+ fieldID: 'third-field',
+ value: 'U03SM0U8TPE',
+ label: '@TestUser',
+ },
+ ],
+ },
+ disabled: false,
+ pending: false,
+ },
+ {
+ id: '1111',
+ name: 'my_webhook',
+ dest: {
+ type: 'webhook-field',
+ values: [
+ {
+ fieldID: 'webhook-url',
+ value: 'https://target.com',
+ label: 'https://target.com',
+ },
+ ],
+ },
+ disabled: false,
+ pending: false,
+ },
+ ],
+ },
+ },
+ })
+ }),
+ ],
+ },
+ },
+ render: function Component(args) {
+ return
+ },
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const MultiContactMethods: Story = {
+ args: {
+ userID: '00000000-0000-0000-0000-000000000002',
+ readOnly: true,
+ },
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement)
+
+ // ensure correct info is displayed for webhook CM
+ await expect(
+ await canvas.findByText('my_webhook (webhook-field)'),
+ ).toBeVisible()
+ await expect(canvas.getByText('docs')).toHaveAttribute(
+ 'href',
+ '/docs#webhooks',
+ )
+
+ // ensure correct info is displayed for triple-field CM
+ await expect(
+ await canvas.findByText('triple contact method (triple-field)'),
+ ).toBeVisible()
+ await expect(await canvas.findByText('+1 555-555-5555')).toBeVisible()
+ await expect(await canvas.findByText('test_user@target.com')).toBeVisible()
+ await expect(await canvas.findByText('@TestUser')).toBeVisible()
+ },
+}