@@ -26,11 +26,19 @@ import { Fragment } from 'react/jsx-runtime';
2626import {
2727 alertLoadingSelector ,
2828 alertsSelector ,
29+ markAllAsRead ,
2930 markAsRead ,
3031 NotificationObject ,
3132 NotificationType ,
3233} from '@/store/notifications/slice' ;
3334import { useStore } from 'react-redux' ;
35+ import { compactFormat } from '@/utils/number' ;
36+ import {
37+ getBgClassNameOfAuraRatingObject ,
38+ getTextClassNameOfAuraRatingObject ,
39+ } from '@/constants' ;
40+ import { useMemo } from 'react' ;
41+ import Tooltip from '@/components/Shared/Tooltip' ;
3442
3543// Define icons for evaluation categories
3644export const subjectViewAsIconColored : {
@@ -92,6 +100,7 @@ export function parseTitleAndDescription(
92100 resolve : ( key : string ) => BrightIdBackupConnection ,
93101 brightId : string | undefined ,
94102 to ?: string | null ,
103+ newState ?: any ,
95104) {
96105 switch ( type ) {
97106 case NotificationType . Evaluation :
@@ -108,39 +117,38 @@ export function parseTitleAndDescription(
108117 ) ;
109118 case NotificationType . LevelIncrease :
110119 if ( profileId === brightId ) {
111- return 'Your ' + description ;
120+ return 'Your Level increased' ;
112121 }
113122 return (
114123 ( resolve ( profileId ) ?. name ?? shortenBrightIdName ( profileId ) ) +
115124 ' ' +
116- description
125+ 'Leveled up'
117126 ) ;
118127 case NotificationType . LevelDecrease :
119128 if ( profileId === brightId ) {
120- return 'Your ' + description ;
129+ return 'Your Level decreased' ;
121130 }
122131 return (
123132 ( resolve ( profileId ) ?. name ?? shortenBrightIdName ( profileId ) ) +
124- ' ' +
125- description
133+ ' Level Decreased'
126134 ) ;
127135 case NotificationType . ScoreDecrease :
128136 if ( profileId === brightId ) {
129- return 'Your ' + description ;
137+ return 'Your Score dropped to ' + compactFormat ( newState ) ;
130138 }
131139 return (
132140 ( resolve ( profileId ) ?. name ?? shortenBrightIdName ( profileId ) ) +
133- ' ' +
134- description
141+ ' Score dropped to ' +
142+ compactFormat ( newState )
135143 ) ;
136144 case NotificationType . ScoreIncrease :
137145 if ( profileId === brightId ) {
138- return 'Your ' + description ;
146+ return 'Your Score increased to ' + compactFormat ( newState ) ;
139147 }
140148 return (
141149 ( resolve ( profileId ) ?. name ?? shortenBrightIdName ( profileId ) ) +
142- ' ' +
143- description
150+ ' Score increased to ' +
151+ compactFormat ( newState )
144152 ) ;
145153 }
146154
@@ -206,6 +214,17 @@ export default function NotificationsPage() {
206214 >
207215 <RefreshCcwIcon className={isLoading ? 'animate-spin' : ''} />
208216 </Button> */ }
217+ { notifications . filter ( ( item ) => ! item . viewed ) . length > 0 && (
218+ < div className = "flex justify-end" >
219+ < Button
220+ size = "sm"
221+ className = ""
222+ onClick = { ( ) => dispatch ( markAllAsRead ( ) ) }
223+ >
224+ Mark all as read
225+ </ Button >
226+ </ div >
227+ ) }
209228 < section className = "mt-8 flex w-full flex-col gap-4" >
210229 < Tabs defaultValue = { categories [ 0 ] } >
211230 < TabsList className = "w-full" >
@@ -291,7 +310,7 @@ function NotificationCard({
291310 < Link to = { `/subject/${ notification . from } ?viewas=${ notification . category } ` } >
292311 < Card
293312 className = { cn (
294- 'my-2 flex items-center gap-4 rounded-lg p-4' ,
313+ 'my-2 flex gap-4 rounded-lg p-4' ,
295314 ! notification . viewed && 'bg-muted' ,
296315 notification . viewed && 'opacity-50' ,
297316 ) }
@@ -311,25 +330,179 @@ function NotificationCard({
311330 resolve ,
312331 brightId ,
313332 notification . to ,
333+ notification . newState ,
314334 ) }
315335 </ div >
316336 < div className = "mt-1 text-xs text-muted-foreground" >
317337 { new Date ( notification . timestamp ) . toLocaleString ( ) }
318338 </ div >
319339 </ div >
320- { ! notification . viewed && (
321- < Button
322- size = "sm"
323- variant = "outline"
324- onClick = { ( e ) => {
325- e . stopPropagation ( ) ;
326- dispatch ( markAsRead ( notification . id ) ) ;
327- } }
328- >
329- Mark as read
330- </ Button >
331- ) }
340+ < div className = "flex flex-col justify-end" >
341+ < div className = "mb-5" >
342+ { notification . type === NotificationType . Evaluation &&
343+ notification . extraPayloads ? (
344+ < EvaluationInfo
345+ impact = { notification . newState ! as number }
346+ rating = { Number ( notification . extraPayloads ?. rating ) }
347+ />
348+ ) : [
349+ NotificationType . LevelDecrease ,
350+ NotificationType . LevelIncrease ,
351+ ] . includes ( notification . type ) ? (
352+ < LevelInfo
353+ previousLevel = { Number ( notification . previousState ) }
354+ newLevel = { Number ( notification . newState ) }
355+ />
356+ ) : [
357+ NotificationType . ScoreDecrease ,
358+ NotificationType . ScoreIncrease ,
359+ ] . includes ( notification . type ) ? (
360+ < ScoreInfo
361+ previousScore = { Number ( notification . previousState ) }
362+ newScore = { Number ( notification . newState ) }
363+ />
364+ ) : null }
365+ </ div >
366+ { ! notification . viewed && (
367+ < div className = "" >
368+ < Button
369+ size = "sm"
370+ variant = "outline"
371+ onClick = { ( e ) => {
372+ e . preventDefault ( ) ;
373+ e . stopPropagation ( ) ;
374+ dispatch ( markAsRead ( notification . id ) ) ;
375+ } }
376+ >
377+ Mark as read
378+ </ Button >
379+ </ div >
380+ ) }
381+ </ div >
332382 </ Card >
333383 </ Link >
334384 ) ;
335385}
386+
387+ function LevelInfo ( {
388+ previousLevel,
389+ newLevel,
390+ } : {
391+ previousLevel : number ;
392+ newLevel : number ;
393+ } ) {
394+ const diff = useMemo (
395+ ( ) => newLevel - previousLevel ,
396+ [ previousLevel , newLevel ] ,
397+ ) ;
398+
399+ const bgColor = getBgClassNameOfAuraRatingObject ( {
400+ rating : ( newLevel - previousLevel ) . toString ( ) ,
401+ } ) ;
402+
403+ return (
404+ < div
405+ className = { `${ bgColor } ml-auto block w-fit rounded-md p-1 text-center text-sm font-semibold` }
406+ >
407+ { diff >= 0 ? '+' : '' } { diff }
408+ </ div >
409+ ) ;
410+ }
411+
412+ function ScoreInfo ( {
413+ previousScore,
414+ newScore,
415+ } : {
416+ previousScore : number ;
417+ newScore : number ;
418+ } ) {
419+ const diff = newScore - previousScore ;
420+ const scoreScaledChange = useMemo ( ( ) => {
421+ const percentChange =
422+ previousScore !== 0 ? ( newScore / previousScore ) * 100 : 0 ;
423+ const scaled = ( percentChange / 100 ) * 4 ;
424+ return ( previousScore < newScore ? 1 : - 1 ) * scaled ;
425+ } , [ newScore , previousScore ] ) ;
426+
427+ const bgColor = getBgClassNameOfAuraRatingObject ( {
428+ rating : Math . floor ( scoreScaledChange ) . toString ( ) ,
429+ } ) ;
430+
431+ return (
432+ < span
433+ className = { `${ bgColor } ml-auto block w-fit rounded-md p-1 text-center text-sm font-semibold` }
434+ >
435+ { diff >= 0 ? '+' : '' } { compactFormat ( diff ) }
436+ </ span >
437+ ) ;
438+ }
439+
440+ function EvaluationInfo ( {
441+ rating,
442+ impact,
443+ } : {
444+ rating : number ;
445+ impact : number ;
446+ } ) {
447+ const bgColor = useMemo ( ( ) => {
448+ if ( rating && Number ( rating ) !== 0 ) {
449+ return getBgClassNameOfAuraRatingObject ( { rating : rating . toString ( ) } ) ;
450+ }
451+ if ( rating >= 2 ) {
452+ return 'bg-pl4' ;
453+ }
454+ if ( rating <= 0 ) {
455+ return 'bg-nl4' ;
456+ }
457+ return 'bg-pl1' ;
458+ } , [ rating ] ) ;
459+
460+ return (
461+ < >
462+ < div className = { `flex flex-col gap-0.5 ${ bgColor } rounded-md py-1.5` } >
463+ < div className = "flex items-center justify-center gap-0.5" >
464+ { inboundConnectionInfo &&
465+ connectionLevelIcons [ inboundConnectionInfo . level ] && (
466+ < Tooltip
467+ content = { `You connected with "${ inboundConnectionInfo ?. level } " to ${ name } ` }
468+ position = "right"
469+ tooltipClassName = "!whitespace-normal !w-40"
470+ >
471+ < img
472+ src = { `/assets/images/Shared/${
473+ connectionLevelIcons [ inboundConnectionInfo . level ]
474+ } .svg`}
475+ className = "h-[18px] w-[18px]"
476+ alt = ""
477+ />
478+ </ Tooltip >
479+ ) }
480+ { ! ! rating && Number ( rating ?. rating ) !== 0 && (
481+ < Tooltip
482+ position = "right"
483+ content = { `You evaluated ${ name } ${
484+ Number ( rating . rating ) > 0 ? `+${ rating . rating } ` : rating . rating
485+ } (${ ratingToText [ rating . rating ] } )`}
486+ >
487+ < p
488+ className = { `text-sm font-bold ${ getTextClassNameOfAuraRatingObject (
489+ rating ,
490+ ) } `}
491+ >
492+ { Number ( rating . rating ) < 0 ? '-' : '+' }
493+ { Math . abs ( Number ( rating . rating ) ) }
494+ </ p >
495+ </ Tooltip >
496+ ) }
497+ </ div >
498+ < p
499+ className = { `impact-percentage ${ getTextClassNameOfAuraRatingObject ( {
500+ rating : rating . toString ( ) ,
501+ } ) } w-full text-center text-[11px] font-bold`}
502+ >
503+ { impact > 0 ? '+' : '-' } { compactFormat ( impact ) }
504+ </ p >
505+ </ div >
506+ </ >
507+ ) ;
508+ }
0 commit comments