Slight notifications refactor
This commit is contained in:
		
							parent
							
								
									54b4f97a84
								
							
						
					
					
						commit
						e969540c72
					
				|  | @ -166,20 +166,6 @@ export default function Notifications() { | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const setNotificationsAsSeen = (notifications: Notification[]) => { |  | ||||||
|   notifications.forEach((notification) => { |  | ||||||
|     if (!notification.isSeen) |  | ||||||
|       updateDoc( |  | ||||||
|         doc(db, `users/${notification.userId}/notifications/`, notification.id), |  | ||||||
|         { |  | ||||||
|           isSeen: true, |  | ||||||
|           viewTime: new Date(), |  | ||||||
|         } |  | ||||||
|       ) |  | ||||||
|   }) |  | ||||||
|   return notifications |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function IncomeNotificationGroupItem(props: { | function IncomeNotificationGroupItem(props: { | ||||||
|   notificationGroup: NotificationGroup |   notificationGroup: NotificationGroup | ||||||
|   className?: string |   className?: string | ||||||
|  | @ -556,6 +542,369 @@ function NotificationGroupItem(props: { | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function NotificationItem(props: { | ||||||
|  |   notification: Notification | ||||||
|  |   justSummary?: boolean | ||||||
|  |   hideTitle?: boolean | ||||||
|  | }) { | ||||||
|  |   const { notification, justSummary, hideTitle } = props | ||||||
|  |   const { | ||||||
|  |     sourceType, | ||||||
|  |     sourceId, | ||||||
|  |     sourceUserName, | ||||||
|  |     sourceUserAvatarUrl, | ||||||
|  |     sourceUpdateType, | ||||||
|  |     reasonText, | ||||||
|  |     reason, | ||||||
|  |     sourceUserUsername, | ||||||
|  |     createdTime, | ||||||
|  |     sourceText, | ||||||
|  |     sourceContractCreatorUsername, | ||||||
|  |     sourceContractSlug, | ||||||
|  |   } = notification | ||||||
|  | 
 | ||||||
|  |   const [defaultNotificationText, setDefaultNotificationText] = | ||||||
|  |     useState<string>('') | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     if (sourceText) { | ||||||
|  |       setDefaultNotificationText(sourceText) | ||||||
|  |     } else if (reasonText) { | ||||||
|  |       // Handle arbitrary notifications with reason text here.
 | ||||||
|  |       setDefaultNotificationText(reasonText) | ||||||
|  |     } | ||||||
|  |   }, [reasonText, sourceText]) | ||||||
|  | 
 | ||||||
|  |   const [highlighted] = useState(!notification.isSeen) | ||||||
|  | 
 | ||||||
|  |   useEffect(() => { | ||||||
|  |     setNotificationsAsSeen([notification]) | ||||||
|  |   }, [notification]) | ||||||
|  | 
 | ||||||
|  |   if (justSummary) { | ||||||
|  |     return ( | ||||||
|  |       <Row className={'items-center text-sm text-gray-500 sm:justify-start'}> | ||||||
|  |         <div className={'line-clamp-1 flex-1 overflow-hidden sm:flex'}> | ||||||
|  |           <div className={'flex pl-1 sm:pl-0'}> | ||||||
|  |             <UserLink | ||||||
|  |               name={sourceUserName || ''} | ||||||
|  |               username={sourceUserUsername || ''} | ||||||
|  |               className={'mr-0 flex-shrink-0'} | ||||||
|  |               justFirstName={true} | ||||||
|  |             /> | ||||||
|  |             <div className={'inline-flex overflow-hidden text-ellipsis pl-1'}> | ||||||
|  |               <span className={'flex-shrink-0'}> | ||||||
|  |                 {sourceType && | ||||||
|  |                   reason && | ||||||
|  |                   getReasonForShowingNotification(notification, true, true)} | ||||||
|  |               </span> | ||||||
|  |               <div className={'ml-1 text-black'}> | ||||||
|  |                 <NotificationTextLabel | ||||||
|  |                   contract={null} | ||||||
|  |                   defaultText={defaultNotificationText} | ||||||
|  |                   className={'line-clamp-1'} | ||||||
|  |                   notification={notification} | ||||||
|  |                   justSummary={true} | ||||||
|  |                 /> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </Row> | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <div | ||||||
|  |       className={clsx( | ||||||
|  |         'bg-white px-2 pt-6 text-sm sm:px-4', | ||||||
|  |         highlighted && 'bg-indigo-200 hover:bg-indigo-100' | ||||||
|  |       )} | ||||||
|  |     > | ||||||
|  |       <a href={getSourceUrl(notification)}> | ||||||
|  |         <Row className={'items-center text-gray-500 sm:justify-start'}> | ||||||
|  |           <Avatar | ||||||
|  |             avatarUrl={sourceUserAvatarUrl} | ||||||
|  |             size={'sm'} | ||||||
|  |             className={'mr-2'} | ||||||
|  |             username={sourceUserName} | ||||||
|  |           /> | ||||||
|  |           <div className={'flex-1 overflow-hidden sm:flex'}> | ||||||
|  |             <div | ||||||
|  |               className={ | ||||||
|  |                 'flex max-w-xl shrink overflow-hidden text-ellipsis pl-1 sm:pl-0' | ||||||
|  |               } | ||||||
|  |             > | ||||||
|  |               {sourceUpdateType != 'closed' && ( | ||||||
|  |                 <UserLink | ||||||
|  |                   name={sourceUserName || ''} | ||||||
|  |                   username={sourceUserUsername || ''} | ||||||
|  |                   className={'mr-0 flex-shrink-0'} | ||||||
|  |                   justFirstName={true} | ||||||
|  |                 /> | ||||||
|  |               )} | ||||||
|  |               {sourceType && reason && ( | ||||||
|  |                 <div className={'inline flex truncate'}> | ||||||
|  |                   <span className={'ml-1 flex-shrink-0'}> | ||||||
|  |                     {getReasonForShowingNotification(notification, false, true)} | ||||||
|  |                   </span> | ||||||
|  |                   {!hideTitle && ( | ||||||
|  |                     <NotificationLink notification={notification} /> | ||||||
|  |                   )} | ||||||
|  |                 </div> | ||||||
|  |               )} | ||||||
|  |               {sourceId && | ||||||
|  |               sourceContractSlug && | ||||||
|  |               sourceContractCreatorUsername ? ( | ||||||
|  |                 <CopyLinkDateTimeComponent | ||||||
|  |                   prefix={sourceContractCreatorUsername} | ||||||
|  |                   slug={sourceContractSlug} | ||||||
|  |                   createdTime={createdTime} | ||||||
|  |                   elementId={getSourceIdForLinkComponent(sourceId)} | ||||||
|  |                   className={'-mx-1 inline-flex sm:inline-block'} | ||||||
|  |                 /> | ||||||
|  |               ) : ( | ||||||
|  |                 <RelativeTimestamp time={createdTime} /> | ||||||
|  |               )} | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </Row> | ||||||
|  |         <div className={'mt-1 ml-1 md:text-base'}> | ||||||
|  |           <NotificationTextLabel | ||||||
|  |             contract={null} | ||||||
|  |             defaultText={defaultNotificationText} | ||||||
|  |             notification={notification} | ||||||
|  |           /> | ||||||
|  |         </div> | ||||||
|  | 
 | ||||||
|  |         <div className={'mt-6 border-b border-gray-300'} /> | ||||||
|  |       </a> | ||||||
|  |     </div> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const setNotificationsAsSeen = (notifications: Notification[]) => { | ||||||
|  |   notifications.forEach((notification) => { | ||||||
|  |     if (!notification.isSeen) | ||||||
|  |       updateDoc( | ||||||
|  |         doc(db, `users/${notification.userId}/notifications/`, notification.id), | ||||||
|  |         { | ||||||
|  |           isSeen: true, | ||||||
|  |           viewTime: new Date(), | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |   }) | ||||||
|  |   return notifications | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function NotificationLink(props: { notification: Notification }) { | ||||||
|  |   const { notification } = props | ||||||
|  |   const { | ||||||
|  |     sourceType, | ||||||
|  |     sourceContractTitle, | ||||||
|  |     sourceContractCreatorUsername, | ||||||
|  |     sourceContractSlug, | ||||||
|  |     sourceSlug, | ||||||
|  |     sourceTitle, | ||||||
|  |   } = notification | ||||||
|  |   return ( | ||||||
|  |     <a | ||||||
|  |       href={ | ||||||
|  |         sourceContractCreatorUsername | ||||||
|  |           ? `/${sourceContractCreatorUsername}/${sourceContractSlug}` | ||||||
|  |           : sourceType === 'group' && sourceSlug | ||||||
|  |           ? `${groupPath(sourceSlug)}` | ||||||
|  |           : '' | ||||||
|  |       } | ||||||
|  |       className={ | ||||||
|  |         'ml-1 inline max-w-xs truncate font-bold text-gray-500 hover:underline hover:decoration-indigo-400 hover:decoration-2 sm:max-w-sm' | ||||||
|  |       } | ||||||
|  |     > | ||||||
|  |       {sourceContractTitle || sourceTitle} | ||||||
|  |     </a> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getSourceUrl(notification: Notification) { | ||||||
|  |   const { | ||||||
|  |     sourceType, | ||||||
|  |     sourceId, | ||||||
|  |     sourceUserUsername, | ||||||
|  |     sourceContractCreatorUsername, | ||||||
|  |     sourceContractSlug, | ||||||
|  |     sourceSlug, | ||||||
|  |   } = notification | ||||||
|  |   if (sourceType === 'follow') return `/${sourceUserUsername}` | ||||||
|  |   if (sourceType === 'group' && sourceSlug) return `${groupPath(sourceSlug)}` | ||||||
|  |   if ( | ||||||
|  |     sourceContractCreatorUsername && | ||||||
|  |     sourceContractSlug && | ||||||
|  |     sourceType === 'user' | ||||||
|  |   ) | ||||||
|  |     return `/${sourceContractCreatorUsername}/${sourceContractSlug}` | ||||||
|  |   if (sourceType === 'tip') | ||||||
|  |     return `/${sourceContractCreatorUsername}/${sourceContractSlug}#${sourceSlug}` | ||||||
|  |   if (sourceContractCreatorUsername && sourceContractSlug) | ||||||
|  |     return `/${sourceContractCreatorUsername}/${sourceContractSlug}#${getSourceIdForLinkComponent( | ||||||
|  |       sourceId ?? '', | ||||||
|  |       sourceType | ||||||
|  |     )}` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getSourceIdForLinkComponent( | ||||||
|  |   sourceId: string, | ||||||
|  |   sourceType?: notification_source_types | ||||||
|  | ) { | ||||||
|  |   switch (sourceType) { | ||||||
|  |     case 'answer': | ||||||
|  |       return `answer-${sourceId}` | ||||||
|  |     case 'comment': | ||||||
|  |       return sourceId | ||||||
|  |     case 'contract': | ||||||
|  |       return '' | ||||||
|  |     default: | ||||||
|  |       return sourceId | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function NotificationTextLabel(props: { | ||||||
|  |   defaultText: string | ||||||
|  |   contract?: Contract | null | ||||||
|  |   notification: Notification | ||||||
|  |   className?: string | ||||||
|  |   justSummary?: boolean | ||||||
|  | }) { | ||||||
|  |   const { contract, className, defaultText, notification, justSummary } = props | ||||||
|  |   const { sourceUpdateType, sourceType, sourceText, sourceContractTitle } = | ||||||
|  |     notification | ||||||
|  |   if (sourceType === 'contract') { | ||||||
|  |     if (justSummary) | ||||||
|  |       return <span>{contract?.question || sourceContractTitle}</span> | ||||||
|  |     if (!sourceText) return <div /> | ||||||
|  |     // Resolved contracts
 | ||||||
|  |     if (sourceType === 'contract' && sourceUpdateType === 'resolved') { | ||||||
|  |       { | ||||||
|  |         if (sourceText === 'YES' || sourceText == 'NO') { | ||||||
|  |           return <BinaryOutcomeLabel outcome={sourceText as any} /> | ||||||
|  |         } | ||||||
|  |         if (sourceText.includes('%')) | ||||||
|  |           return ( | ||||||
|  |             <ProbPercentLabel prob={parseFloat(sourceText.replace('%', ''))} /> | ||||||
|  |           ) | ||||||
|  |         if (sourceText === 'CANCEL') return <CancelLabel /> | ||||||
|  |         if (sourceText === 'MKT' || sourceText === 'PROB') return <MultiLabel /> | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Close date will be a number - it looks better without it
 | ||||||
|  |     if (sourceUpdateType === 'closed') { | ||||||
|  |       return <div /> | ||||||
|  |     } | ||||||
|  |     // Updated contracts
 | ||||||
|  |     // Description will be in default text
 | ||||||
|  |     if (parseInt(sourceText) > 0) { | ||||||
|  |       return ( | ||||||
|  |         <span> | ||||||
|  |           Updated close time: {new Date(parseInt(sourceText)).toLocaleString()} | ||||||
|  |         </span> | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  |   } else if (sourceType === 'user' && sourceText) { | ||||||
|  |     return ( | ||||||
|  |       <span> | ||||||
|  |         As a thank you, we sent you{' '} | ||||||
|  |         <span className="text-primary"> | ||||||
|  |           {formatMoney(parseInt(sourceText))} | ||||||
|  |         </span> | ||||||
|  |         ! | ||||||
|  |       </span> | ||||||
|  |     ) | ||||||
|  |   } else if (sourceType === 'liquidity' && sourceText) { | ||||||
|  |     return ( | ||||||
|  |       <span className="text-blue-400">{formatMoney(parseInt(sourceText))}</span> | ||||||
|  |     ) | ||||||
|  |   } else if ((sourceType === 'bonus' || sourceType === 'tip') && sourceText) { | ||||||
|  |     return ( | ||||||
|  |       <span className="text-primary"> | ||||||
|  |         {'+' + formatMoney(parseInt(sourceText))} | ||||||
|  |       </span> | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  |   // return default text
 | ||||||
|  |   return ( | ||||||
|  |     <div className={className ? className : 'line-clamp-4 whitespace-pre-line'}> | ||||||
|  |       <Linkify text={defaultText} /> | ||||||
|  |     </div> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getReasonForShowingNotification( | ||||||
|  |   notification: Notification, | ||||||
|  |   simple?: boolean, | ||||||
|  |   replaceOn?: boolean | ||||||
|  | ) { | ||||||
|  |   const { sourceType, sourceUpdateType, reason, sourceSlug } = notification | ||||||
|  |   let reasonText: string | ||||||
|  |   switch (sourceType) { | ||||||
|  |     case 'comment': | ||||||
|  |       if (reason === 'reply_to_users_answer') | ||||||
|  |         reasonText = !simple ? 'replied to you on' : 'replied' | ||||||
|  |       else if (reason === 'tagged_user') | ||||||
|  |         reasonText = !simple ? 'tagged you on' : 'tagged you' | ||||||
|  |       else if (reason === 'reply_to_users_comment') | ||||||
|  |         reasonText = !simple ? 'replied to you on' : 'replied' | ||||||
|  |       else if (reason === 'on_users_contract') | ||||||
|  |         reasonText = !simple ? `commented on your question` : 'commented' | ||||||
|  |       else if (reason === 'on_contract_with_users_comment') | ||||||
|  |         reasonText = `commented on` | ||||||
|  |       else if (reason === 'on_contract_with_users_answer') | ||||||
|  |         reasonText = `commented on` | ||||||
|  |       else if (reason === 'on_contract_with_users_shares_in') | ||||||
|  |         reasonText = `commented on` | ||||||
|  |       else reasonText = `commented on` | ||||||
|  |       break | ||||||
|  |     case 'contract': | ||||||
|  |       if (reason === 'you_follow_user') reasonText = 'asked' | ||||||
|  |       else if (sourceUpdateType === 'resolved') reasonText = `resolved` | ||||||
|  |       else if (sourceUpdateType === 'closed') | ||||||
|  |         reasonText = `Please resolve your question` | ||||||
|  |       else reasonText = `updated` | ||||||
|  |       break | ||||||
|  |     case 'answer': | ||||||
|  |       if (reason === 'on_users_contract') reasonText = `answered your question ` | ||||||
|  |       else if (reason === 'on_contract_with_users_comment') | ||||||
|  |         reasonText = `answered` | ||||||
|  |       else if (reason === 'on_contract_with_users_answer') | ||||||
|  |         reasonText = `answered` | ||||||
|  |       else if (reason === 'on_contract_with_users_shares_in') | ||||||
|  |         reasonText = `answered` | ||||||
|  |       else reasonText = `answered` | ||||||
|  |       break | ||||||
|  |     case 'follow': | ||||||
|  |       reasonText = 'followed you' | ||||||
|  |       break | ||||||
|  |     case 'liquidity': | ||||||
|  |       reasonText = 'added liquidity to your question' | ||||||
|  |       break | ||||||
|  |     case 'group': | ||||||
|  |       reasonText = 'added you to the group' | ||||||
|  |       break | ||||||
|  |     case 'user': | ||||||
|  |       if (sourceSlug && reason === 'user_joined_to_bet_on_your_market') | ||||||
|  |         reasonText = 'joined to bet on your market' | ||||||
|  |       else if (sourceSlug) reasonText = 'joined because you shared' | ||||||
|  |       else reasonText = 'joined because of you' | ||||||
|  |       break | ||||||
|  |     default: | ||||||
|  |       reasonText = '' | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <span className={'flex-shrink-0'}> | ||||||
|  |       {replaceOn ? reasonText.replace(' on', '') : reasonText} | ||||||
|  |     </span> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // TODO: where should we put referral bonus notifications?
 | // TODO: where should we put referral bonus notifications?
 | ||||||
| function NotificationSettings() { | function NotificationSettings() { | ||||||
|   const user = useUser() |   const user = useUser() | ||||||
|  | @ -751,352 +1100,3 @@ function NotificationSettings() { | ||||||
|     </div> |     </div> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| function NotificationLink(props: { notification: Notification }) { |  | ||||||
|   const { notification } = props |  | ||||||
|   const { |  | ||||||
|     sourceType, |  | ||||||
|     sourceContractTitle, |  | ||||||
|     sourceContractCreatorUsername, |  | ||||||
|     sourceContractSlug, |  | ||||||
|     sourceSlug, |  | ||||||
|     sourceTitle, |  | ||||||
|   } = notification |  | ||||||
|   return ( |  | ||||||
|     <a |  | ||||||
|       href={ |  | ||||||
|         sourceContractCreatorUsername |  | ||||||
|           ? `/${sourceContractCreatorUsername}/${sourceContractSlug}` |  | ||||||
|           : sourceType === 'group' && sourceSlug |  | ||||||
|           ? `${groupPath(sourceSlug)}` |  | ||||||
|           : '' |  | ||||||
|       } |  | ||||||
|       className={ |  | ||||||
|         'ml-1 inline max-w-xs truncate font-bold text-gray-500 hover:underline hover:decoration-indigo-400 hover:decoration-2 sm:max-w-sm' |  | ||||||
|       } |  | ||||||
|     > |  | ||||||
|       {sourceContractTitle || sourceTitle} |  | ||||||
|     </a> |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function getSourceUrl(notification: Notification) { |  | ||||||
|   const { |  | ||||||
|     sourceType, |  | ||||||
|     sourceId, |  | ||||||
|     sourceUserUsername, |  | ||||||
|     sourceContractCreatorUsername, |  | ||||||
|     sourceContractSlug, |  | ||||||
|     sourceSlug, |  | ||||||
|   } = notification |  | ||||||
|   if (sourceType === 'follow') return `/${sourceUserUsername}` |  | ||||||
|   if (sourceType === 'group' && sourceSlug) return `${groupPath(sourceSlug)}` |  | ||||||
|   if ( |  | ||||||
|     sourceContractCreatorUsername && |  | ||||||
|     sourceContractSlug && |  | ||||||
|     sourceType === 'user' |  | ||||||
|   ) |  | ||||||
|     return `/${sourceContractCreatorUsername}/${sourceContractSlug}` |  | ||||||
|   if (sourceType === 'tip') |  | ||||||
|     return `/${sourceContractCreatorUsername}/${sourceContractSlug}#${sourceSlug}` |  | ||||||
|   if (sourceContractCreatorUsername && sourceContractSlug) |  | ||||||
|     return `/${sourceContractCreatorUsername}/${sourceContractSlug}#${getSourceIdForLinkComponent( |  | ||||||
|       sourceId ?? '', |  | ||||||
|       sourceType |  | ||||||
|     )}` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function getSourceIdForLinkComponent( |  | ||||||
|   sourceId: string, |  | ||||||
|   sourceType?: notification_source_types |  | ||||||
| ) { |  | ||||||
|   switch (sourceType) { |  | ||||||
|     case 'answer': |  | ||||||
|       return `answer-${sourceId}` |  | ||||||
|     case 'comment': |  | ||||||
|       return sourceId |  | ||||||
|     case 'contract': |  | ||||||
|       return '' |  | ||||||
|     default: |  | ||||||
|       return sourceId |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function NotificationItem(props: { |  | ||||||
|   notification: Notification |  | ||||||
|   justSummary?: boolean |  | ||||||
|   hideTitle?: boolean |  | ||||||
| }) { |  | ||||||
|   const { notification, justSummary, hideTitle } = props |  | ||||||
|   const { |  | ||||||
|     sourceType, |  | ||||||
|     sourceId, |  | ||||||
|     sourceUserName, |  | ||||||
|     sourceUserAvatarUrl, |  | ||||||
|     sourceUpdateType, |  | ||||||
|     reasonText, |  | ||||||
|     reason, |  | ||||||
|     sourceUserUsername, |  | ||||||
|     createdTime, |  | ||||||
|     sourceText, |  | ||||||
|     sourceContractCreatorUsername, |  | ||||||
|     sourceContractSlug, |  | ||||||
|   } = notification |  | ||||||
| 
 |  | ||||||
|   const [defaultNotificationText, setDefaultNotificationText] = |  | ||||||
|     useState<string>('') |  | ||||||
| 
 |  | ||||||
|   useEffect(() => { |  | ||||||
|     if (sourceText) { |  | ||||||
|       setDefaultNotificationText(sourceText) |  | ||||||
|     } else if (reasonText) { |  | ||||||
|       // Handle arbitrary notifications with reason text here.
 |  | ||||||
|       setDefaultNotificationText(reasonText) |  | ||||||
|     } |  | ||||||
|   }, [reasonText, sourceText]) |  | ||||||
| 
 |  | ||||||
|   const [highlighted] = useState(!notification.isSeen) |  | ||||||
| 
 |  | ||||||
|   useEffect(() => { |  | ||||||
|     setNotificationsAsSeen([notification]) |  | ||||||
|   }, [notification]) |  | ||||||
| 
 |  | ||||||
|   if (justSummary) { |  | ||||||
|     return ( |  | ||||||
|       <Row className={'items-center text-sm text-gray-500 sm:justify-start'}> |  | ||||||
|         <div className={'line-clamp-1 flex-1 overflow-hidden sm:flex'}> |  | ||||||
|           <div className={'flex pl-1 sm:pl-0'}> |  | ||||||
|             <UserLink |  | ||||||
|               name={sourceUserName || ''} |  | ||||||
|               username={sourceUserUsername || ''} |  | ||||||
|               className={'mr-0 flex-shrink-0'} |  | ||||||
|               justFirstName={true} |  | ||||||
|             /> |  | ||||||
|             <div className={'inline-flex overflow-hidden text-ellipsis pl-1'}> |  | ||||||
|               <span className={'flex-shrink-0'}> |  | ||||||
|                 {sourceType && |  | ||||||
|                   reason && |  | ||||||
|                   getReasonForShowingNotification(notification, true, true)} |  | ||||||
|               </span> |  | ||||||
|               <div className={'ml-1 text-black'}> |  | ||||||
|                 <NotificationTextLabel |  | ||||||
|                   contract={null} |  | ||||||
|                   defaultText={defaultNotificationText} |  | ||||||
|                   className={'line-clamp-1'} |  | ||||||
|                   notification={notification} |  | ||||||
|                   justSummary={true} |  | ||||||
|                 /> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </Row> |  | ||||||
|     ) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return ( |  | ||||||
|     <div |  | ||||||
|       className={clsx( |  | ||||||
|         'bg-white px-2 pt-6 text-sm sm:px-4', |  | ||||||
|         highlighted && 'bg-indigo-200 hover:bg-indigo-100' |  | ||||||
|       )} |  | ||||||
|     > |  | ||||||
|       <a href={getSourceUrl(notification)}> |  | ||||||
|         <Row className={'items-center text-gray-500 sm:justify-start'}> |  | ||||||
|           <Avatar |  | ||||||
|             avatarUrl={sourceUserAvatarUrl} |  | ||||||
|             size={'sm'} |  | ||||||
|             className={'mr-2'} |  | ||||||
|             username={sourceUserName} |  | ||||||
|           /> |  | ||||||
|           <div className={'flex-1 overflow-hidden sm:flex'}> |  | ||||||
|             <div |  | ||||||
|               className={ |  | ||||||
|                 'flex max-w-xl shrink overflow-hidden text-ellipsis pl-1 sm:pl-0' |  | ||||||
|               } |  | ||||||
|             > |  | ||||||
|               {sourceUpdateType != 'closed' && ( |  | ||||||
|                 <UserLink |  | ||||||
|                   name={sourceUserName || ''} |  | ||||||
|                   username={sourceUserUsername || ''} |  | ||||||
|                   className={'mr-0 flex-shrink-0'} |  | ||||||
|                   justFirstName={true} |  | ||||||
|                 /> |  | ||||||
|               )} |  | ||||||
|               {sourceType && reason && ( |  | ||||||
|                 <div className={'inline flex truncate'}> |  | ||||||
|                   <span className={'ml-1 flex-shrink-0'}> |  | ||||||
|                     {getReasonForShowingNotification(notification, false, true)} |  | ||||||
|                   </span> |  | ||||||
|                   {!hideTitle && ( |  | ||||||
|                     <NotificationLink notification={notification} /> |  | ||||||
|                   )} |  | ||||||
|                 </div> |  | ||||||
|               )} |  | ||||||
|               {sourceId && |  | ||||||
|               sourceContractSlug && |  | ||||||
|               sourceContractCreatorUsername ? ( |  | ||||||
|                 <CopyLinkDateTimeComponent |  | ||||||
|                   prefix={sourceContractCreatorUsername} |  | ||||||
|                   slug={sourceContractSlug} |  | ||||||
|                   createdTime={createdTime} |  | ||||||
|                   elementId={getSourceIdForLinkComponent(sourceId)} |  | ||||||
|                   className={'-mx-1 inline-flex sm:inline-block'} |  | ||||||
|                 /> |  | ||||||
|               ) : ( |  | ||||||
|                 <RelativeTimestamp time={createdTime} /> |  | ||||||
|               )} |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </Row> |  | ||||||
|         <div className={'mt-1 ml-1 md:text-base'}> |  | ||||||
|           <NotificationTextLabel |  | ||||||
|             contract={null} |  | ||||||
|             defaultText={defaultNotificationText} |  | ||||||
|             notification={notification} |  | ||||||
|           /> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <div className={'mt-6 border-b border-gray-300'} /> |  | ||||||
|       </a> |  | ||||||
|     </div> |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function NotificationTextLabel(props: { |  | ||||||
|   defaultText: string |  | ||||||
|   contract?: Contract | null |  | ||||||
|   notification: Notification |  | ||||||
|   className?: string |  | ||||||
|   justSummary?: boolean |  | ||||||
| }) { |  | ||||||
|   const { contract, className, defaultText, notification, justSummary } = props |  | ||||||
|   const { sourceUpdateType, sourceType, sourceText, sourceContractTitle } = |  | ||||||
|     notification |  | ||||||
|   if (sourceType === 'contract') { |  | ||||||
|     if (justSummary) |  | ||||||
|       return <span>{contract?.question || sourceContractTitle}</span> |  | ||||||
|     if (!sourceText) return <div /> |  | ||||||
|     // Resolved contracts
 |  | ||||||
|     if (sourceType === 'contract' && sourceUpdateType === 'resolved') { |  | ||||||
|       { |  | ||||||
|         if (sourceText === 'YES' || sourceText == 'NO') { |  | ||||||
|           return <BinaryOutcomeLabel outcome={sourceText as any} /> |  | ||||||
|         } |  | ||||||
|         if (sourceText.includes('%')) |  | ||||||
|           return ( |  | ||||||
|             <ProbPercentLabel prob={parseFloat(sourceText.replace('%', ''))} /> |  | ||||||
|           ) |  | ||||||
|         if (sourceText === 'CANCEL') return <CancelLabel /> |  | ||||||
|         if (sourceText === 'MKT' || sourceText === 'PROB') return <MultiLabel /> |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     // Close date will be a number - it looks better without it
 |  | ||||||
|     if (sourceUpdateType === 'closed') { |  | ||||||
|       return <div /> |  | ||||||
|     } |  | ||||||
|     // Updated contracts
 |  | ||||||
|     // Description will be in default text
 |  | ||||||
|     if (parseInt(sourceText) > 0) { |  | ||||||
|       return ( |  | ||||||
|         <span> |  | ||||||
|           Updated close time: {new Date(parseInt(sourceText)).toLocaleString()} |  | ||||||
|         </span> |  | ||||||
|       ) |  | ||||||
|     } |  | ||||||
|   } else if (sourceType === 'user' && sourceText) { |  | ||||||
|     return ( |  | ||||||
|       <span> |  | ||||||
|         As a thank you, we sent you{' '} |  | ||||||
|         <span className="text-primary"> |  | ||||||
|           {formatMoney(parseInt(sourceText))} |  | ||||||
|         </span> |  | ||||||
|         ! |  | ||||||
|       </span> |  | ||||||
|     ) |  | ||||||
|   } else if (sourceType === 'liquidity' && sourceText) { |  | ||||||
|     return ( |  | ||||||
|       <span className="text-blue-400">{formatMoney(parseInt(sourceText))}</span> |  | ||||||
|     ) |  | ||||||
|   } else if ((sourceType === 'bonus' || sourceType === 'tip') && sourceText) { |  | ||||||
|     return ( |  | ||||||
|       <span className="text-primary"> |  | ||||||
|         {'+' + formatMoney(parseInt(sourceText))} |  | ||||||
|       </span> |  | ||||||
|     ) |  | ||||||
|   } |  | ||||||
|   // return default text
 |  | ||||||
|   return ( |  | ||||||
|     <div className={className ? className : 'line-clamp-4 whitespace-pre-line'}> |  | ||||||
|       <Linkify text={defaultText} /> |  | ||||||
|     </div> |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function getReasonForShowingNotification( |  | ||||||
|   notification: Notification, |  | ||||||
|   simple?: boolean, |  | ||||||
|   replaceOn?: boolean |  | ||||||
| ) { |  | ||||||
|   const { sourceType, sourceUpdateType, reason, sourceSlug } = notification |  | ||||||
|   let reasonText: string |  | ||||||
|   switch (sourceType) { |  | ||||||
|     case 'comment': |  | ||||||
|       if (reason === 'reply_to_users_answer') |  | ||||||
|         reasonText = !simple ? 'replied to you on' : 'replied' |  | ||||||
|       else if (reason === 'tagged_user') |  | ||||||
|         reasonText = !simple ? 'tagged you on' : 'tagged you' |  | ||||||
|       else if (reason === 'reply_to_users_comment') |  | ||||||
|         reasonText = !simple ? 'replied to you on' : 'replied' |  | ||||||
|       else if (reason === 'on_users_contract') |  | ||||||
|         reasonText = !simple ? `commented on your question` : 'commented' |  | ||||||
|       else if (reason === 'on_contract_with_users_comment') |  | ||||||
|         reasonText = `commented on` |  | ||||||
|       else if (reason === 'on_contract_with_users_answer') |  | ||||||
|         reasonText = `commented on` |  | ||||||
|       else if (reason === 'on_contract_with_users_shares_in') |  | ||||||
|         reasonText = `commented on` |  | ||||||
|       else reasonText = `commented on` |  | ||||||
|       break |  | ||||||
|     case 'contract': |  | ||||||
|       if (reason === 'you_follow_user') reasonText = 'asked' |  | ||||||
|       else if (sourceUpdateType === 'resolved') reasonText = `resolved` |  | ||||||
|       else if (sourceUpdateType === 'closed') |  | ||||||
|         reasonText = `Please resolve your question` |  | ||||||
|       else reasonText = `updated` |  | ||||||
|       break |  | ||||||
|     case 'answer': |  | ||||||
|       if (reason === 'on_users_contract') reasonText = `answered your question ` |  | ||||||
|       else if (reason === 'on_contract_with_users_comment') |  | ||||||
|         reasonText = `answered` |  | ||||||
|       else if (reason === 'on_contract_with_users_answer') |  | ||||||
|         reasonText = `answered` |  | ||||||
|       else if (reason === 'on_contract_with_users_shares_in') |  | ||||||
|         reasonText = `answered` |  | ||||||
|       else reasonText = `answered` |  | ||||||
|       break |  | ||||||
|     case 'follow': |  | ||||||
|       reasonText = 'followed you' |  | ||||||
|       break |  | ||||||
|     case 'liquidity': |  | ||||||
|       reasonText = 'added liquidity to your question' |  | ||||||
|       break |  | ||||||
|     case 'group': |  | ||||||
|       reasonText = 'added you to the group' |  | ||||||
|       break |  | ||||||
|     case 'user': |  | ||||||
|       if (sourceSlug && reason === 'user_joined_to_bet_on_your_market') |  | ||||||
|         reasonText = 'joined to bet on your market' |  | ||||||
|       else if (sourceSlug) reasonText = 'joined because you shared' |  | ||||||
|       else reasonText = 'joined because of you' |  | ||||||
|       break |  | ||||||
|     default: |  | ||||||
|       reasonText = '' |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return ( |  | ||||||
|     <span className={'flex-shrink-0'}> |  | ||||||
|       {replaceOn ? reasonText.replace(' on', '') : reasonText} |  | ||||||
|     </span> |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user