UNPKG

@suprsend/react

Version:

The react library for using SuprSend features like inbox, preferences etc

1 lines 117 kB
{"version":3,"file":"index.cjs","sources":["../../src/Feed/utils/styles.ts","../../src/Feed/InboxPopover/Bell/BellIcon.tsx","../../src/Feed/InboxPopover/Bell/Bell.tsx","../../src/Feed/InboxPopover/Badge/Badge.tsx","../../src/Feed/NotificationFeed/NotificationFeedHeader.tsx","../../src/Feed/utils/index.ts","../../src/Feed/interface.ts","../../src/Feed/NotificationCard/Icons/AvatarIcon.tsx","../../src/Feed/NotificationCard/Icons/MoreIcon.tsx","../../src/Feed/NotificationCard/Icons/PinnedNotificationIcon.tsx","../../src/Feed/NotificationCard/Icons/UnReadIcon.tsx","../../src/Feed/NotificationCard/Icons/ReadIcon.tsx","../../src/Feed/NotificationCard/Icons/ArchiveIcon.tsx","../../src/Feed/NotificationCard/NotificationCard.tsx","../../src/Feed/utils/useIntersectionObserver.ts","../../src/Feed/NotificationCard/ClickableNotificationCard.tsx","../../src/Feed/NotificationCard/ToastNotificationCard.tsx","../../src/Feed/utils/useDebounceValue.ts","../../src/Feed/NotificationFeed/NotificationFeed.tsx","../../src/Feed/utils/useClickOutside.ts","../../src/Feed/InboxPopover/InboxPopover.tsx","../../src/Feed/InboxPopover/index.tsx"],"sourcesContent":["import styled from '@emotion/styled';\n\nexport const lightColors = {\n primary: '#2E70E8',\n primaryText: '#1E293B',\n secondaryText: '#475569',\n border: '#E2E8F0',\n main: '#FFFFFF',\n error: '#B42318',\n};\n\nexport const darkColors = {\n primary: '#2E70E8',\n primaryText: '#EFEFEF',\n secondaryText: '#CBD5E1',\n border: '#3A4A61',\n main: '#1D2635',\n error: '#F97066',\n};\n\nexport const CText = styled.p`\n font-size: 14px;\n font-weight: 400;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,\n Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';\n line-height: 20px;\n color: ${lightColors.primaryText};\n margin: 0px;\n`;\n\nexport const HelperText = styled(CText)`\n font-size: 12px;\n color: ${lightColors.secondaryText};\n`;\n\nexport const HeadingText = styled(CText)`\n font-size: 16px;\n font-weight: 500;\n`;\n\nexport const darkTheme = {\n bell: { color: '#fff' },\n badge: { backgroundColor: darkColors.primary },\n header: {\n container: {\n backgroundColor: darkColors.main,\n borderBottom: `0.5px solid ${darkColors.border}`,\n boxShadow: '0 0 5px 0 rgba(0, 0, 0, 0.5)',\n },\n headerText: { color: darkColors.primaryText },\n markAllReadText: { color: darkColors.primary },\n },\n tabs: {\n color: darkColors.primaryText,\n unselectedColor: darkColors.secondaryText + 'D9',\n bottomColor: darkColors.primary,\n badgeColor: 'rgba(100, 116, 139, 0.5)',\n badgeText: darkColors.primaryText,\n },\n notificationsContainer: {\n container: {\n backgroundColor: darkColors.main,\n borderColor: darkColors.border,\n },\n noNotificationsText: {\n color: darkColors.primaryText,\n },\n noNotificationsSubtext: {\n color: darkColors.secondaryText,\n },\n loader: { color: darkColors.primary },\n },\n notification: {\n container: {\n borderBottom: `1px solid ${darkColors.border}`,\n readBackgroundColor: darkColors.main,\n unreadBackgroundColor: '#273244',\n hoverBackgroundColor: '#2D3A4D',\n },\n pinnedText: {\n color: darkColors?.secondaryText,\n },\n headerText: { color: darkColors.primaryText },\n bodyText: {\n color: darkColors.secondaryText,\n blockquoteColor: 'rgba(100, 116, 139, 0.5)',\n },\n unseenDot: { backgroundColor: darkColors.primary },\n createdOnText: { color: darkColors.secondaryText },\n subtext: { color: '#94a3b8' },\n actions: [\n { container: { backgroundColor: darkColors.primary } },\n {\n container: {\n borderColor: darkColors.border,\n backgroundColor: 'transparent',\n hoverBackgroundColor: darkColors.main,\n },\n text: { color: darkColors.secondaryText },\n },\n ],\n expiresText: {\n backgroundColor: 'rgba(100, 116, 139, 0.5)',\n color: darkColors.secondaryText,\n expiringBackgroundColor: 'rgba(217, 45, 32, 0.15)',\n expiringColor: darkColors.error,\n },\n actionsMenuIcon: {\n color: darkColors.secondaryText,\n hoverBackgroundColor: 'rgba(100, 116, 139, 0.5)',\n },\n actionsMenu: {\n backgroundColor: darkColors.main,\n borderColor: darkColors.border,\n },\n actionsMenuItem: { hoverBackgroundColor: 'rgba(100, 116, 139, 0.2)' },\n actionsMenuItemIcon: { color: darkColors.secondaryText },\n actionsMenuItemText: {\n color: darkColors.secondaryText,\n },\n },\n toast: {\n container: {\n backgroundColor: darkColors.main,\n borderColor: darkColors.border,\n },\n headerText: { color: darkColors.primaryText },\n bodyText: {\n color: darkColors.secondaryText,\n blockquoteColor: darkColors.border,\n tableBorderColor: darkColors.border,\n },\n },\n};\n","import { IconProps } from '../../interface';\nimport { lightColors } from '../../utils/styles';\n\nexport default function BellIcon({ style }: IconProps) {\n const height = style?.height || 24;\n const width = style?.width || 24;\n const color = style?.color || lightColors.primaryText;\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={width}\n height={height}\n color={color}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9\"\n />\n </svg>\n );\n}\n","import BellIcon from './BellIcon';\nimport { BellProps } from '../../interface';\n\nexport default function Bell({ bellComponent, style }: BellProps) {\n if (bellComponent) {\n const BellComponent = bellComponent;\n return <BellComponent />;\n }\n\n return <BellIcon style={style} />;\n}\n","import styled from '@emotion/styled';\nimport { lightColors, CText } from '../../utils/styles';\nimport { BadgeProps } from '../../interface';\n\nexport default function Badge({ count, badgeComponent, style }: BadgeProps) {\n if (count <= 0) return null;\n\n if (badgeComponent) {\n const BagdeComponent = badgeComponent;\n return <BagdeComponent count={count} />;\n }\n return <CountText style={style}>{count}</CountText>;\n}\n\nconst CountText = styled(CText)`\n position: absolute;\n right: -3px;\n top: -7px;\n display: inline-block;\n font-size: 10px;\n line-height: 1;\n padding: 3px 6px;\n border-radius: 50%;\n background-color: ${lightColors.primary};\n color: ${lightColors.main};\n text-align: center;\n`;\n","import { Dispatch, SetStateAction } from 'react';\nimport styled from '@emotion/styled';\nimport {\n IStore,\n useFeedClient,\n useFeedData,\n ApiResponse,\n useTranslations,\n useFeed,\n} from '@suprsend/react-core';\nimport { CText, HeadingText, lightColors } from '../utils/styles';\nimport { TabsThemeProps, IHeaderTheme } from '../interface';\n\ninterface InternalHeaderRightComponentProps {\n header?: IHeaderTheme;\n markAllRead: () => Promise<ApiResponse> | undefined;\n}\n\nfunction InternalHeaderRightComponent({\n header,\n markAllRead,\n}: InternalHeaderRightComponentProps) {\n const { t } = useTranslations();\n return (\n <AllReadButton\n style={header?.markAllReadText}\n onClick={(e) => {\n e.stopPropagation();\n markAllRead();\n }}\n >\n {t('markAllAsRead')}\n </AllReadButton>\n );\n}\n\ninterface IHeaderProps {\n style?: {\n header?: {\n container?: React.CSSProperties;\n headerText?: React.CSSProperties;\n markAllReadText?: React.CSSProperties;\n };\n tabs?: TabsThemeProps;\n };\n tabBadgeComponent?: React.FC<{ count: number }>;\n showUnreadCountOnTabs?: boolean;\n headerRightComponent?: React.FC<{\n markAllRead: () => void;\n closeInboxPopover: () => void;\n }>;\n setPopoverOpen?: Dispatch<SetStateAction<boolean>>;\n}\n\nexport default function Header({\n style,\n tabBadgeComponent,\n headerRightComponent,\n showUnreadCountOnTabs = true,\n setPopoverOpen,\n}: IHeaderProps) {\n const feedClient = useFeedClient();\n const feedData = useFeedData();\n const feed = useFeed();\n const { t } = useTranslations();\n\n const stores = feedClient?.feedOptions.stores;\n const hasStores = !!(stores && stores.length > 0);\n const TabBadgeComponent = tabBadgeComponent;\n const HeaderRightComponent = headerRightComponent;\n const header = style?.header;\n const tabs = style?.tabs;\n\n return (\n <Container style={header?.container}>\n <TopContainer hasStores={hasStores}>\n <HeaderText style={header?.headerText}>{t('notifications')}</HeaderText>\n {HeaderRightComponent ? (\n <HeaderRightComponent\n markAllRead={() => feedClient?.markAllAsRead()}\n closeInboxPopover={() => {\n setPopoverOpen?.(false);\n }}\n />\n ) : (\n <InternalHeaderRightComponent\n header={header}\n markAllRead={() => feedClient?.markAllAsRead()}\n />\n )}\n </TopContainer>\n {hasStores && (\n <TabsContainer>\n {stores.map((store: IStore, index: number) => {\n const isActiveTab = feedData?.store.storeId === store.storeId;\n const tabUnreadCount = feedData?.meta[store.storeId] || 0;\n const showBadge = showUnreadCountOnTabs && tabUnreadCount > 0;\n const selectedTabBottomColor = isActiveTab\n ? tabs?.bottomColor\n : 'none';\n const textColor = isActiveTab\n ? tabs?.color\n : tabs?.unselectedColor || tabs?.color;\n const label =\n feed?.stores?.find(\n (storeItem) => storeItem.storeId === store.storeId\n )?.label || store.label;\n\n return (\n <TabContainer\n style={{ borderBottomColor: selectedTabBottomColor }}\n key={index}\n selected={isActiveTab}\n onClick={() => {\n feedClient?.changeActiveStore(store.storeId);\n }}\n >\n <TabText\n selected={isActiveTab}\n style={{\n ...tabs,\n color: textColor,\n }}\n >\n {label}\n </TabText>\n {showBadge &&\n (TabBadgeComponent ? (\n <TabBadgeComponent count={tabUnreadCount} />\n ) : (\n <TabBadge\n style={{\n backgroundColor: tabs?.badgeColor,\n color: tabs?.badgeText,\n }}\n >\n <TabBadgeText count={tabUnreadCount}>\n {tabUnreadCount}\n </TabBadgeText>\n </TabBadge>\n ))}\n </TabContainer>\n );\n })}\n </TabsContainer>\n )}\n </Container>\n );\n}\n\nconst Container = styled.div`\n position: sticky;\n top: 0;\n padding: 16px;\n padding-bottom: 0px;\n z-index: 1000;\n background-color: ${lightColors.main};\n box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.1);\n`;\n\nconst TopContainer = styled.div<{ hasStores: boolean }>`\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: ${(props) => (props.hasStores ? '16px' : '0px')};\n padding-bottom: ${(props) => (props.hasStores ? '0px' : '16px')};\n`;\n\nconst TabsContainer = styled.div`\n display: flex;\n overflow-x: scroll;\n -ms-overflow-style: none;\n scrollbar-width: none;\n &::-webkit-scrollbar {\n display: none;\n }\n`;\n\nconst TabContainer = styled.div<{ selected: boolean }>`\n padding: 5px 15px 3px 15px;\n border-bottom: ${(props) => {\n return props.selected ? `2px solid ${lightColors.primary}` : 'none';\n }};\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 5px;\n`;\n\nconst TabText = styled(CText)<{ selected: boolean }>`\n font-size: 14px;\n font-weight: 600;\n color: ${(props) => {\n return props.selected\n ? lightColors.primaryText\n : lightColors.secondaryText + 'D9';\n }};\n`;\n\nconst HeaderText = styled(HeadingText)`\n font-weight: 600;\n font-size: 16px;\n`;\n\nconst AllReadButton = styled(HeadingText)`\n color: ${lightColors.primary};\n font-size: 12px;\n cursor: pointer;\n`;\n\nconst TabBadge = styled.div`\n height: 18px;\n width: 20px;\n border-radius: 50%;\n background-color: rgba(100, 116, 139, 0.09);\n display: flex;\n align-items: center;\n justify-content: center;\n color: ${lightColors.primaryText};\n`;\n\nconst TabBadgeText = styled.p<{ count: number }>`\n margin: 0px;\n padding: 0px;\n font-size: ${(props) => {\n return props?.count > 99 ? '8px' : '10px';\n }};\n font-weight: 600;\n line-height: 1;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,\n Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';\n`;\n","import { Dictionary, ITranslations } from '@suprsend/react-core';\n\nexport function formatActionLink(link: string) {\n if (!link) return;\n\n return link.startsWith('http') || link.startsWith('/')\n ? link\n : `https://${link}`;\n}\n\nexport async function isImgUrl(url?: string): Promise<boolean> {\n if (!url) return false;\n\n const img = new window.Image();\n img.src = url;\n return new Promise((resolve) => {\n img.onerror = () => resolve(false);\n img.onload = () => resolve(true);\n });\n}\n\nexport function getLongFormattedTime(\n value: number,\n unit: string,\n t: (key: keyof ITranslations) => string\n) {\n switch (unit) {\n case 'second':\n return `1 ${t('minute')}`;\n case 'minute':\n return value === 1\n ? `${value} ${t('minute')}`\n : `${value} ${t('minutes')}`;\n case 'hour':\n return value === 1 ? `${value} ${t('hour')}` : `${value} ${t('hours')}`;\n case 'day':\n return value === 1 ? `${value} ${t('day')}` : `${value} ${t('days')}`;\n case 'week':\n return value === 1 ? `${value} ${t('week')}` : `${value} ${t('weeks')}`;\n case 'month':\n return value === 1 ? `${value} ${t('month')}` : `${value} ${t('months')}`;\n case 'year':\n return value === 1 ? `${value} ${t('year')}` : `${value} ${t('years')}`;\n default:\n return value;\n }\n}\n\nexport function getShortFormattedTime(value: number, unit: string) {\n switch (unit) {\n case 'second':\n return '1m';\n case 'minute':\n return `${value}m`;\n case 'hour':\n return `${value}h`;\n case 'day':\n return `${value}d`;\n case 'week':\n return `${value}w`;\n case 'month':\n return `${value}mo`;\n case 'year':\n return `${value}y`;\n default:\n return value;\n }\n}\n\nfunction isObject(item: unknown) {\n return item && typeof item === 'object' && !Array.isArray(item);\n}\n\nexport function mergeDeep(target?: Dictionary, source?: Dictionary) {\n const output = Object.assign({}, target);\n if (target && isObject(target) && source && isObject(source)) {\n Object.keys(source).forEach((key) => {\n if (isObject(source[key])) {\n if (!(key in target)) {\n Object.assign(output, { [key]: source[key] });\n } else {\n output[key] = mergeDeep(\n target[key] as Dictionary,\n source[key] as Dictionary\n );\n }\n } else {\n Object.assign(output, { [key]: source[key] });\n }\n });\n }\n return output;\n}\n\nfunction hasTouchSupport() {\n return 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n}\n\nexport function isMobile() {\n return hasTouchSupport();\n}\n","import {\n IRemoteNotification,\n IFeedOptions,\n ApiResponse,\n} from '@suprsend/react-core';\nimport { Placement } from '@popperjs/core';\nimport { Dispatch, SetStateAction } from 'react';\n\nexport enum ThemeType {\n LIGHT = 'light',\n DARK = 'dark',\n}\n\nexport interface BadgeThemeProps extends React.CSSProperties {\n backgroundColor?: string;\n color?: string;\n}\n\nexport interface BadgeProps {\n count: number;\n badgeComponent?: React.FC<{ count: number }>;\n style?: BadgeThemeProps;\n}\n\nexport interface BellProps {\n bellComponent?: React.FC;\n style?: IconThemeProps;\n}\n\nexport interface IconProps {\n style?: IconThemeProps;\n}\n\nexport interface IconThemeProps {\n height?: number | string;\n width?: number | string;\n color?: string;\n}\n\nexport interface AvatarIconProps {\n type?: ThemeType;\n}\n\nexport interface TabsThemeProps {\n color?: string;\n unselectedColor?: string;\n bottomColor?: string;\n badgeColor?: string;\n badgeText?: string;\n}\n\nexport interface LoaderThemeProps {\n color?: string;\n}\n\nexport interface NotificationCardContainerThemeProps\n extends React.CSSProperties {\n borderBottom?: string | number;\n readBackgroundColor?: string;\n unreadBackgroundColor?: string;\n hoverBackgroundColor?: string;\n}\n\nexport interface NotificationCardBodyTextThemeProps\n extends React.CSSProperties {\n color?: string;\n blockquoteColor?: string;\n tableBorderColor?: string;\n linkColor?: string;\n}\n\nexport interface NotificationCardExpriesTextThemeProps\n extends React.CSSProperties {\n expiringBackgroundColor?: string;\n expiringColor?: string;\n}\n\nexport type HandleActionClick = (\n e: React.MouseEvent<HTMLSpanElement, MouseEvent>,\n clickData: ClickHandlerPayload\n) => void;\n\nexport interface ToastNotificationProps {\n notificationData: IRemoteNotification;\n hideAvatar?: boolean;\n themeType?: ThemeType;\n theme?: ToastNotificationCardTheme;\n disableMarkdown?: boolean;\n}\n\ninterface ToastNotificationCardTheme {\n avatar?: React.CSSProperties;\n headerText?: React.CSSProperties;\n bodyText?: NotificationCardBodyTextThemeProps;\n container?: React.CSSProperties;\n}\n\nexport interface NotificationCardProps {\n notification?: INotificationCardTheme;\n notificationData: IRemoteNotification;\n handleActionClick: HandleActionClick;\n notificationComponent?: React.FC<CustomNotificationCard>;\n hideAvatar?: boolean;\n themeType?: ThemeType;\n primaryActionClickHandler?: (notificationData: IRemoteNotification) => void;\n secondaryActionClickHandler?: (notificationData: IRemoteNotification) => void;\n theme?: INotificationCardTheme;\n disableMarkdown?: boolean;\n}\n\nexport interface BodyMarkdownProps {\n body: string;\n handleActionClick?: HandleActionClick;\n style?: NotificationCardBodyTextThemeProps;\n disableMarkdown?: boolean;\n}\n\nexport interface NotificationCardActionButtonViewThemeProps\n extends React.CSSProperties {\n hoverBackgroundColor?: string;\n}\n\nexport interface CardActionMenuIconThemeProps extends IconThemeProps {\n hoverBackgroundColor?: string;\n}\n\nexport interface CardActionsMenuItem extends React.CSSProperties {\n hoverBackgroundColor?: string;\n}\n\nexport interface CustomNotificationCard {\n notificationData: IRemoteNotification;\n markAsRead: (e?: Event) => Promise<ApiResponse> | undefined;\n markAsUnread: (e?: Event) => Promise<ApiResponse> | undefined;\n markAsArchived: (e?: Event) => Promise<ApiResponse> | undefined;\n markAsInteracted: (e?: Event) => Promise<ApiResponse> | undefined;\n}\n\nexport interface ClickHandlerPayload {\n target?: boolean;\n customClickHandler?: (notificationData: IRemoteNotification) => void;\n url?: string;\n type: string;\n}\n\nexport interface ExpiryTimerProps {\n dateInput?: number;\n style?: NotificationCardExpriesTextThemeProps;\n}\n\nexport interface ClickableNotificationProps {\n notificationData: IRemoteNotification;\n notificationClickHandler?: (notificationData: IRemoteNotification) => void;\n notificationComponent?: React.FC<CustomNotificationCard>;\n hideAvatar?: boolean;\n themeType?: ThemeType;\n primaryActionClickHandler?: (notification: IRemoteNotification) => void;\n secondaryActionClickHandler?: (notification: IRemoteNotification) => void;\n theme?: INotificationCardTheme;\n scrollRef?: React.MutableRefObject<HTMLInputElement | undefined>;\n setUnseenNotifications?: Dispatch<SetStateAction<string[]>>;\n unseenNotifications?: string[];\n enableIntersectionObserver?: boolean;\n disableMarkdown?: boolean;\n}\n\nexport interface NotificationFeedProps {\n notificationClickHandler?: (notification: IRemoteNotification) => void;\n primaryActionClickHandler?: (notification: IRemoteNotification) => void;\n secondaryActionClickHandler?: (notification: IRemoteNotification) => void;\n loaderComponent?: React.FC;\n noNotificationsComponent?: React.FC;\n tabBadgeComponent?: React.FC<{ count: number }>;\n notificationComponent?: React.FC<CustomNotificationCard>;\n headerRightComponent?: React.FC<{\n markAllRead: () => void;\n closeInboxPopover: () => void;\n }>;\n pagination?: boolean;\n showUnreadCountOnTabs?: boolean;\n hideAvatar?: boolean;\n themeType?: ThemeType;\n theme?: INotificationFeedTheme;\n popover?: boolean;\n setPopoverOpen?: Dispatch<SetStateAction<boolean>>;\n disableMarkdown?: boolean;\n}\n\nexport interface INotificationsContainerTheme {\n container?: React.CSSProperties;\n noNotificationsText?: React.CSSProperties;\n noNotificationsSubtext?: React.CSSProperties;\n loader?: LoaderThemeProps;\n}\n\nexport interface IHeaderTheme {\n container?: React.CSSProperties;\n headerText?: React.CSSProperties;\n markAllReadText?: React.CSSProperties;\n}\n\nexport interface INotificationCardTheme {\n container?: NotificationCardContainerThemeProps;\n pinnedIcon?: IconThemeProps;\n pinnedText?: React.CSSProperties;\n headerText?: React.CSSProperties;\n bodyText?: NotificationCardBodyTextThemeProps;\n unseenDot?: React.CSSProperties;\n avatar?: React.CSSProperties;\n createdOnText?: React.CSSProperties;\n subtext?: React.CSSProperties;\n expiresText?: NotificationCardExpriesTextThemeProps;\n actions?: Array<{\n container?: NotificationCardActionButtonViewThemeProps;\n text?: React.CSSProperties;\n }>;\n actionsMenuIcon?: CardActionMenuIconThemeProps;\n actionsMenu?: React.CSSProperties;\n actionsMenuItem?: CardActionsMenuItem;\n actionsMenuItemIcon?: IconThemeProps;\n actionsMenuItemText?: React.CSSProperties;\n}\n\nexport interface INotificationFeedTheme {\n header?: IHeaderTheme;\n tabs?: TabsThemeProps;\n notificationsContainer?: INotificationsContainerTheme;\n notification?: INotificationCardTheme;\n}\n\nexport interface ITheme extends INotificationFeedTheme {\n bell?: IconThemeProps;\n badge?: BadgeThemeProps;\n}\n\nexport interface InboxPopoverProps extends NotificationFeedProps {\n bellComponent?: React.FC;\n badgeComponent?: React.FC<{ count: number }>;\n popperPosition?: Placement;\n theme?: ITheme;\n}\n\nexport interface InboxProps extends IFeedOptions, InboxPopoverProps {\n children?: React.ReactNode;\n}\n","import { AvatarIconProps, ThemeType } from '../../interface';\n\nconst AvatarIcon = ({ type }: AvatarIconProps) => {\n if (type === ThemeType.DARK) {\n return (\n <svg\n width=\"36\"\n height=\"36\"\n viewBox=\"0 0 36 36\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"18\" cy=\"18\" r=\"18\" fill=\"#334155\" />\n <path\n d=\"M23.8641 14.2836C23.8641 17.3522 21.4556 19.8399 18.4844 19.8399C15.5132 19.8399 13.1047 17.3522 13.1047 14.2836C13.1047 11.215 15.5132 8.72754 18.4844 8.72754C21.4556 8.72754 23.8641 11.215 23.8641 14.2836Z\"\n fill=\"#94A3B8\"\n />\n <path\n d=\"M23.8643 20.9316H13.1051C11.1039 20.9316 9.37694 22.0734 8.4502 23.75C10.6277 27.0754 14.3128 29.2659 18.4848 29.2659C22.6568 29.2659 26.3418 27.0754 28.5195 23.75C27.5913 22.0734 25.866 20.9316 23.8645 20.9316H23.8643Z\"\n fill=\"#94A3B8\"\n />\n </svg>\n );\n }\n return (\n <svg\n width=\"36\"\n height=\"36\"\n viewBox=\"0 0 36 36\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"18\" cy=\"18\" r=\"18\" fill=\"#CBD5E1\" />\n <path\n d=\"M23.8641 14.2836C23.8641 17.3522 21.4556 19.8399 18.4844 19.8399C15.5132 19.8399 13.1047 17.3522 13.1047 14.2836C13.1047 11.215 15.5132 8.72754 18.4844 8.72754C21.4556 8.72754 23.8641 11.215 23.8641 14.2836Z\"\n fill=\"white\"\n />\n <path\n d=\"M23.8643 20.9316H13.1051C11.1039 20.9316 9.37694 22.0734 8.4502 23.75C10.6277 27.0754 14.3128 29.2659 18.4848 29.2659C22.6568 29.2659 26.3418 27.0754 28.5195 23.75C27.5913 22.0734 25.866 20.9316 23.8645 20.9316H23.8643Z\"\n fill=\"white\"\n />\n </svg>\n );\n};\n\nexport default AvatarIcon;\n","import { lightColors } from '../../utils/styles';\nimport { IconProps } from '../../interface';\n\nconst MoreIcon = ({ style }: IconProps) => {\n const height = style?.height || 20;\n const width = style?.width || 20;\n const color = style?.color || lightColors.secondaryText;\n\n return (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11C18.4477 11 18 11.4477 18 12C18 12.5523 18.4477 13 19 13Z\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5 13C5.55228 13 6 12.5523 6 12C6 11.4477 5.55228 11 5 11C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13Z\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n};\nexport default MoreIcon;\n","import { IconProps } from '../../interface';\n\nconst PinnedNotificationIcon = ({ style }: IconProps) => {\n const height = style?.height || 13;\n const width = style?.width || 13;\n const color = style?.color || '#DC6803';\n\n return (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 16 17\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.58984 2.9305C7.38193 2.44536 7.27797 2.2028 7.10998 2.09261C6.96308 1.99626 6.78408 1.96179 6.6119 1.99669C6.415 2.03661 6.22839 2.22321 5.85518 2.59643L2.42642 6.02519C2.0532 6.39841 1.86659 6.58502 1.82668 6.78191C1.79177 6.95409 1.82624 7.13309 1.9226 7.28C2.03278 7.44799 2.27535 7.55194 2.76048 7.75986L4.42339 8.47253C4.49393 8.50277 4.5292 8.51788 4.56228 8.53678C4.59166 8.55356 4.61972 8.57256 4.64622 8.59361C4.67605 8.6173 4.70318 8.64444 4.75745 8.69871L5.79805 9.7393C5.88293 9.82418 5.92537 9.86662 5.95909 9.91498C5.98903 9.9579 6.0138 10.0042 6.03291 10.0529C6.05444 10.1078 6.06621 10.1666 6.08975 10.2844L6.57835 12.7273C6.70532 13.3622 6.76881 13.6796 6.93618 13.8281C7.08198 13.9575 7.27711 14.0166 7.47019 13.9898C7.69183 13.9591 7.92074 13.7302 8.37855 13.2724L13.1024 8.54856C13.5602 8.09075 13.7891 7.86185 13.8198 7.64021C13.8466 7.44713 13.7875 7.252 13.6581 7.10619C13.5096 6.93882 13.1922 6.87534 12.5573 6.74836L10.1143 6.25977C9.99663 6.23622 9.93777 6.22445 9.88289 6.20293C9.83418 6.18382 9.78788 6.15904 9.74496 6.12911C9.69661 6.09538 9.65416 6.05294 9.56928 5.96806L8.52869 4.92747C8.47442 4.8732 8.44729 4.84606 8.42359 4.81624C8.40255 4.78974 8.38355 4.76168 8.36676 4.73229C8.34787 4.69922 8.33275 4.66395 8.30252 4.5934L7.58984 2.9305Z\"\n fill={color}\n />\n <path\n d=\"M10.7405 10.9105L14.5117 14.6817M8.52869 4.92747L9.56928 5.96806C9.65416 6.05294 9.69661 6.09538 9.74496 6.12911C9.78788 6.15904 9.83418 6.18382 9.88289 6.20293C9.93777 6.22445 9.99663 6.23622 10.1143 6.25977L12.5573 6.74836C13.1922 6.87534 13.5096 6.93882 13.6581 7.10619C13.7875 7.252 13.8466 7.44713 13.8198 7.64021C13.7891 7.86185 13.5602 8.09075 13.1024 8.54856L8.37855 13.2724C7.92074 13.7302 7.69183 13.9591 7.47019 13.9898C7.27711 14.0166 7.08198 13.9575 6.93618 13.8281C6.76881 13.6796 6.70532 13.3622 6.57835 12.7273L6.08975 10.2844C6.06621 10.1666 6.05444 10.1078 6.03291 10.0529C6.0138 10.0042 5.98903 9.9579 5.95909 9.91498C5.92537 9.86662 5.88293 9.82418 5.79805 9.7393L4.75745 8.69871C4.70318 8.64444 4.67605 8.6173 4.64622 8.59361C4.61972 8.57256 4.59166 8.55356 4.56228 8.53678C4.5292 8.51788 4.49393 8.50277 4.42339 8.47253L2.76048 7.75986C2.27535 7.55194 2.03278 7.44799 1.9226 7.28C1.82624 7.13309 1.79177 6.95409 1.82668 6.78191C1.86659 6.58502 2.0532 6.39841 2.42642 6.02519L5.85517 2.59643C6.22839 2.22321 6.415 2.03661 6.6119 1.99669C6.78408 1.96179 6.96308 1.99626 7.10998 2.09261C7.27797 2.2028 7.38193 2.44536 7.58984 2.9305L8.30252 4.5934C8.33275 4.66395 8.34787 4.69922 8.36676 4.73229C8.38355 4.76168 8.40255 4.78974 8.42359 4.81624C8.44729 4.84606 8.47442 4.8732 8.52869 4.92747Z\"\n stroke={color}\n strokeWidth=\"1.33333\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n};\n\nexport default PinnedNotificationIcon;\n","import { lightColors } from '../../utils/styles';\nimport { IconProps } from '../../interface';\n\nconst UnReadIcon = ({ style }: IconProps) => {\n const height = style?.height || 16;\n const width = style?.width || 16;\n const color = style?.color || lightColors.primaryText;\n\n return (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M14.416 3H4.00013C2.34327 3 1.00013 4.34315 1.00013 6V6.98313C0.999958 6.99375 0.999958 7.00437 1.00013 7.01499V18C1.00013 19.6569 2.34327 21 4.00013 21H20.0001C21.657 21 23.0001 19.6569 23.0001 18V9.21078H21.0001V18C21.0001 18.5523 20.5524 19 20.0001 19H4.00013C3.44784 19 3.00013 18.5523 3.00013 18V8.82027L10.4338 13.544L10.4392 13.5474C10.9071 13.8405 11.448 13.996 12.0001 13.996C12.5522 13.996 13.0932 13.8405 13.5611 13.5474L13.5665 13.544L19.5 9.21078H16.5L12.4992 11.8526L12.497 11.854C12.3479 11.9468 12.1758 11.996 12.0001 11.996C11.8245 11.996 11.6524 11.9468 11.5033 11.854L3.00013 6.45063V6C3.00013 5.44772 3.44784 5 4.00013 5H14.416V3Z\"\n fill={color}\n />\n <circle cx=\"20\" cy=\"4\" r=\"4\" fill={color} />\n </svg>\n );\n};\n\nexport default UnReadIcon;\n","import { lightColors } from '../../utils/styles';\nimport { IconProps } from '../../interface';\n\nconst ReadIcon = ({ style }: IconProps) => {\n const height = style?.height || 16;\n const width = style?.width || 16;\n const color = style?.color || lightColors.primaryText;\n\n return (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 16 17\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M14.1334 6.26471C14.4667 6.51805 14.6667 6.91138 14.6667 7.33138V13.998C14.6667 14.3517 14.5262 14.6908 14.2762 14.9409C14.0261 15.1909 13.687 15.3314 13.3334 15.3314H2.66671C2.31309 15.3314 1.97395 15.1909 1.7239 14.9409C1.47385 14.6908 1.33337 14.3517 1.33337 13.998V7.33138C1.33337 7.12439 1.38157 6.92024 1.47414 6.7351C1.56671 6.54995 1.70111 6.38891 1.86671 6.26471L7.20004 2.26471C7.43084 2.09162 7.71155 1.99805 8.00004 1.99805C8.28853 1.99805 8.56925 2.09162 8.80004 2.26471L14.1334 6.26471Z\"\n stroke={color}\n strokeWidth=\"1.33333\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.6667 7.33105L8.68668 11.1311C8.48086 11.26 8.24289 11.3284 8.00001 11.3284C7.75713 11.3284 7.51916 11.26 7.31334 11.1311L1.33334 7.33105\"\n stroke={color}\n strokeWidth=\"1.33333\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n};\n\nexport default ReadIcon;\n","import { lightColors } from '../../utils/styles';\nimport { IconProps } from '../../interface';\n\nconst ArchiveIcon = ({ style }: IconProps) => {\n const height = style?.height || 17;\n const width = style?.width || 16;\n const color = style?.color || lightColors.secondaryText;\n\n return (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 16 17\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M14 2.33789H1.99998C1.63179 2.33789 1.33331 2.63637 1.33331 3.00456V5.00456C1.33331 5.37275 1.63179 5.67122 1.99998 5.67122H14C14.3682 5.67122 14.6666 5.37275 14.6666 5.00456V3.00456C14.6666 2.63637 14.3682 2.33789 14 2.33789Z\"\n stroke={color}\n strokeWidth=\"1.33333\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M2.66669 5.67188V13.0052C2.66669 13.3588 2.80716 13.698 3.05721 13.948C3.30726 14.1981 3.6464 14.3385 4.00002 14.3385H12C12.3536 14.3385 12.6928 14.1981 12.9428 13.948C13.1929 13.698 13.3334 13.3588 13.3334 13.0052V5.67188\"\n stroke={color}\n strokeWidth=\"1.33333\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M6.66669 8.33789H9.33335\"\n stroke={color}\n strokeWidth=\"1.33333\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n};\n\nexport default ArchiveIcon;\n","import { useEffect, useMemo, useState } from 'react';\nimport styled from '@emotion/styled';\nimport Markdown, { PluggableList } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport rehypeRaw from 'rehype-raw';\nimport TimeAgo from 'react-timeago';\nimport {\n useFeedClient,\n useFeedData,\n useTranslations,\n} from '@suprsend/react-core';\nimport { Pluggable } from 'unified';\nimport { CText, HelperText, lightColors } from '../utils/styles';\nimport {\n isImgUrl,\n getLongFormattedTime,\n getShortFormattedTime,\n isMobile,\n} from '../utils';\nimport {\n ArchiveIcon,\n AvatarIcon,\n MoreIcon,\n PinnedNotificationIcon,\n ReadIcon,\n UnReadIcon,\n} from './Icons';\nimport {\n NotificationCardProps,\n ExpiryTimerProps,\n BodyMarkdownProps,\n} from '../interface';\n\nfunction ExpiryTime({ dateInput, style }: ExpiryTimerProps) {\n const [, setTime] = useState(Date.now());\n const { t } = useTranslations();\n\n useEffect(() => {\n const interval = setInterval(() => setTime(Date.now()), 10000);\n return () => {\n clearInterval(interval);\n };\n }, []);\n\n if (typeof dateInput !== 'number') return;\n\n const isExpiring = dateInput - Date.now() <= 3600000;\n const expiredAlready = Date.now() >= dateInput;\n\n return (\n <div>\n <ExpiresText\n style={{\n ...style,\n color: isExpiring\n ? style?.expiringColor || lightColors.error\n : style?.color || lightColors.secondaryText,\n backgroundColor: isExpiring\n ? style?.expiringBackgroundColor || 'rgba(217, 45, 32, 0.09)'\n : style?.backgroundColor || 'rgba(100, 116, 139, 0.09)',\n }}\n >\n {t('expiresIn')}{' '}\n {expiredAlready ? (\n 'a minute'\n ) : (\n <TimeAgo\n date={dateInput}\n live={false}\n formatter={(value, unit) => getLongFormattedTime(value, unit, t)}\n />\n )}\n </ExpiresText>\n </div>\n );\n}\n\nexport function BodyMarkdown({\n body,\n handleActionClick,\n style,\n disableMarkdown,\n}: BodyMarkdownProps) {\n const tableBorderColor =\n style?.tableBorderColor || 'rgba(100, 116, 139, 0.3)';\n const blockquoteColor = style?.blockquoteColor || 'rgba(100, 116, 139, 0.3)';\n const linkColor = style?.linkColor || lightColors.primary;\n\n return (\n <BodyText style={style}>\n {disableMarkdown ? (\n body\n ) : (\n <Markdown\n remarkPlugins={[remarkGfm as Pluggable] as PluggableList}\n rehypePlugins={[rehypeRaw as Pluggable] as PluggableList}\n components={{\n a({ children, href, style }) {\n return (\n <span\n onClick={(e) => {\n e.preventDefault();\n handleActionClick?.(e, {\n type: 'markdown_link',\n url: href,\n });\n }}\n style={{\n color: linkColor,\n textDecoration: 'none',\n ...(style || {}),\n }}\n >\n {children}\n </span>\n );\n },\n p({ children, style }) {\n return (\n <p\n style={{\n margin: 0,\n overflowWrap: 'anywhere',\n ...(style || {}),\n }}\n >\n {children}\n </p>\n );\n },\n blockquote({ children, style }) {\n return (\n <blockquote\n style={{\n margin: 0,\n paddingLeft: 10,\n borderLeft: `3px ${blockquoteColor} solid`,\n marginBottom: 5,\n marginTop: 5,\n ...(style || {}),\n }}\n >\n {children}\n </blockquote>\n );\n },\n ul({ children, style }) {\n return (\n <ul\n style={{\n whiteSpace: 'normal',\n margin: 0,\n paddingLeft: 10,\n ...(style || {}),\n }}\n >\n {children}\n </ul>\n );\n },\n ol({ children, style }) {\n return (\n <ol\n style={{\n whiteSpace: 'normal',\n margin: 0,\n paddingLeft: 10,\n ...(style || {}),\n }}\n >\n {children}\n </ol>\n );\n },\n img(props) {\n return (\n <img\n style={{\n maxWidth: '100%',\n objectFit: 'contain',\n ...(props?.style || {}),\n }}\n {...props}\n />\n );\n },\n table({ children, style }) {\n return (\n <table\n style={{\n overflowWrap: 'break-word',\n borderCollapse: 'collapse',\n ...(style || {}),\n }}\n >\n {children}\n </table>\n );\n },\n th({ children, style }) {\n return (\n <th\n style={{\n textAlign: 'left',\n whiteSpace: 'nowrap',\n border: `1px solid ${tableBorderColor}`,\n padding: 5,\n ...(style || {}),\n }}\n >\n {children}\n </th>\n );\n },\n td({ children, style }) {\n return (\n <td\n style={{\n border: `1px solid ${tableBorderColor}`,\n padding: 5,\n ...(style || {}),\n }}\n >\n {children}\n </td>\n );\n },\n h1({ children, style }) {\n return (\n <h1\n style={{\n margin: 0,\n ...(style || {}),\n }}\n >\n {children}\n </h1>\n );\n },\n h2({ children, style }) {\n return (\n <h2\n style={{\n margin: 0,\n ...(style || {}),\n }}\n >\n {children}\n </h2>\n );\n },\n h3({ children, style }) {\n return (\n <h3\n style={{\n margin: 0,\n ...(style || {}),\n }}\n >\n {children}\n </h3>\n );\n },\n h4({ children, style }) {\n return (\n <h4\n style={{\n margin: 0,\n ...(style || {}),\n }}\n >\n {children}\n </h4>\n );\n },\n h5({ children, style }) {\n return (\n <h5\n style={{\n margin: 0,\n ...(style || {}),\n }}\n >\n {children}\n </h5>\n );\n },\n h6({ children, style }) {\n return (\n <h6\n style={{\n margin: 0,\n ...(style || {}),\n }}\n >\n {children}\n </h6>\n );\n },\n script() {\n return null;\n },\n link() {\n return null;\n },\n }}\n >\n {body\n ?.replaceAll('\\\\\\n', '&nbsp;')\n ?.replaceAll('\\n', ' \\n')\n ?.replaceAll('&nbsp;', '&nbsp; \\n')}\n </Markdown>\n )}\n </BodyText>\n );\n}\n\nexport default function Notification({\n notificationData,\n handleActionClick,\n notificationComponent,\n hideAvatar,\n themeType,\n primaryActionClickHandler,\n secondaryActionClickHandler,\n theme,\n disableMarkdown,\n}: NotificationCardProps) {\n const [validAvatar, setValidAvatar] = useState(false);\n const [showMore, setShowMore] = useState(false);\n const [moreOpen, setMoreOpen] = useState(false);\n\n const feedClient = useFeedClient();\n const feedData = useFeedData();\n const { t } = useTranslations();\n\n const { message, read_on, created_on } = notificationData;\n\n const notificationsList = feedData?.notifications;\n const actionOne = message?.actions?.[0];\n const actionTwo = message?.actions?.[1];\n const hasButtons = actionOne || actionTwo;\n const lastNotification = notificationsList?.length\n ? notificationsList[notificationsList.length - 1]\n : null;\n const isLastNotification = lastNotification?.n_id === notificationData.n_id;\n\n useEffect(() => {\n const isValidAvatar = isImgUrl(message?.avatar?.avatar_url);\n isValidAvatar.then((res) => setValidAvatar(res));\n }, [notificationData]);\n\n const isPlatformMobile = useMemo(isMobile, []);\n\n if (notificationComponent) {\n const NotificationComponent = notificationComponent;\n return (\n <NotificationComponent\n notificationData={notificationData}\n markAsRead={(e?: Event) => {\n e?.stopPropagation?.();\n return feedClient?.markAsRead(notificationData.n_id);\n }}\n markAsUnread={(e?: Event) => {\n e?.stopPropagation?.();\n return feedClient?.markAsUnread(notificationData.n_id);\n }}\n markAsArchived={(e?: Event) => {\n e?.stopPropagation?.();\n return feedClient?.markAsArchived(notificationData.n_id);\n }}\n markAsInteracted={(e?: Event) => {\n e?.stopPropagation?.();\n return feedClient?.markAsInteracted(notificationData.n_id);\n }}\n />\n );\n }\n\n return (\n <Container\n style={theme?.container}\n read={!!read_on}\n onMouseEnter={() => {\n setShowMore(true);\n setMoreOpen(false);\n }}\n onMouseLeave={() => {\n setShowMore(false);\n setMoreOpen(false);\n }}\n onClick={(e) => {\n if (moreOpen) {\n e.stopPropagation();\n setMoreOpen(false);\n }\n }}\n >\n {notificationData.is_pinned && (\n <PinnedView hideAvatar={hideAvatar}>\n <PinnedNotificationIcon style={theme?.pinnedIcon} />\n <PinnedNotificationText style={theme?.pinnedText}>\n {t('pinned')}\n </PinnedNotificationText>\n </PinnedView>\n )}\n <NotificationView>\n <LeftView>\n <LeftAvatarView>\n <UnseenDot style={theme?.unseenDot} show={!read_on} />\n {!hideAvatar && (\n <AvatarView\n onClick={(e) => {\n const avatarData = message?.avatar;\n handleActionClick(e, {\n type: 'avatar',\n url: avatarData?.action_url,\n });\n }}\n >\n {message?.avatar?.avatar_url && validAvatar ? (\n <AvatarImage\n src={message.avatar.avatar_url}\n alt=\"avatar\"\n style={theme?.avatar}\n />\n ) : (\n <AvatarIcon type={themeType} />\n )}\n </AvatarView>\n )}\n </LeftAvatarView>\n <ContentView>\n {message.header && (\n <HeaderText style={theme?.headerText}>\n {message.header}\n </HeaderText>\n )}\n <BodyMarkdown\n body={message.text}\n handleActionClick={handleActionClick}\n style={theme?.bodyText}\n disableMarkdown={disableMarkdown}\n />\n {!!message?.subtext?.text && (\n <SubTextView\n link={message?.subtext?.action_url}\n onClick={(e) => {\n const subTextData = message?.subtext;\n handleActionClick(e, {\n type: 'subtext',\n url: subTextData?.action_url,\n });\n }}\n >\n <SubText style={theme?.subtext}>{message.subtext.text}</SubText>\n </SubTextView>\n )}\n {notificationData.expiry && notificationData?.is_expiry_visible && (\n <ExpiryTime\n dateInput={notificationData.expiry}\n style={theme?.expiresText}\n />\n )}\n {hasButtons && (\n <ButtonContainer>\n {actionOne && (\n <ButtonView\n style={theme?.actions?.[0]?.container}\n onClick={(e) => {\n handleActionClick(e, {\n type: 'primary_action_button',\n url: actionOne.url,\n target: actionOne.open_in_new_tab,\n customClickHandler: primaryActionClickHandler,\n });\n }}\n >\n <ButtonText style={theme?.actions?.[0]?.text}>\n {actionOne.name}\n </ButtonText>\n </ButtonView>\n )}\n {actionTwo && (\n <ButtonOutlineView\n style={theme?.actions?.[1]?.container}\n onClick={(e) => {\n handleActionClick(e, {\n type: 'secondary_action_button',\n url: actionTwo.url,\n target: actionTwo.open_in_new_tab,\n customClickHandler: secondaryActionClickHandler,\n });\n }}\n >\n <ButtonOutlineText style={theme?.actions?.[1]?.text}>\n {actionTwo.name}\n </ButtonOutlineText>\n </ButtonOutlineView>\n )}\n </ButtonContainer>\n )}\n </ContentView>\n </LeftView>\n <RightView>\n <CreatedText style={theme?.createdOnText}>\n <TimeAgo\n date={created_on}\n live={false}\n formatter={getShortFormattedTime}\n />\n </CreatedText>\n <CMenuView showMore={showMore || isPlatformMobile}>\n <CMenuButton\n hoverBGColor={theme?.actionsMenuIcon?.hoverBackgroundColor}\n isPlatformMobile={isPlatformMobile}\n onClick={(e) => {\n e.stopPropagation();\n setMoreOpen((prev) => !prev);\n }}\n >\n <MoreIcon style={theme?.actionsMenuIcon} />