@@ -95,6 +95,7 @@ function mockNearbyEventStore(event: {
9595 meeting_link ?: string ;
9696 location ?: string ;
9797 description ?: string ;
98+ participants_json ?: string ;
9899 is_all_day ?: boolean ;
99100} ) {
100101 return mockNearbyEventStoreMany ( [ event ] ) ;
@@ -108,6 +109,7 @@ function mockNearbyEventStoreMany(
108109 meeting_link ?: string ;
109110 location ?: string ;
110111 description ?: string ;
112+ participants_json ?: string ;
111113 is_all_day ?: boolean ;
112114 } > ,
113115) {
@@ -126,6 +128,7 @@ function mockNearbyEventStoreMany(
126128 meeting_link : event . meeting_link ,
127129 location : event . location ,
128130 description : event . description ,
131+ participants_json : event . participants_json ,
129132 is_all_day : event . is_all_day ?? false ,
130133 } ;
131134 } ) ,
@@ -784,7 +787,9 @@ describe("ListenerProvider detect events", () => {
784787 app_ids : [ "at.studio.AsideBrowser" ] ,
785788 event_ids : [ "event-1" ] ,
786789 } ,
787- options : [ "Design sync" ] ,
790+ title : "Are you in Design sync right now?" ,
791+ action_label : "Yes" ,
792+ options : null ,
788793 footer : {
789794 text : "Ignore Google Meet?" ,
790795 actionLabel : "Yes" ,
@@ -802,6 +807,56 @@ describe("ListenerProvider detect events", () => {
802807 ) ;
803808 } ) ;
804809
810+ test ( "uses event participants for nearby mic notification copy" , async ( ) => {
811+ const store = createListenerStore ( ) ;
812+
813+ vi . useFakeTimers ( ) ;
814+ vi . setSystemTime ( new Date ( "2026-06-24T02:09:00.000Z" ) ) ;
815+ ( useStoreMock as any ) . mockReturnValue (
816+ mockNearbyEventStore ( {
817+ title : "Design sync" ,
818+ started_at : "2026-06-24T02:09:00.000Z" ,
819+ participants_json : JSON . stringify ( [
820+ { name : "John" , email : "john@example.com" , is_current_user : true } ,
821+ { name : "Artem" , email : "artem@example.com" } ,
822+ ] ) ,
823+ } ) ,
824+ ) ;
825+
826+ render (
827+ < ListenerProvider store = { store } >
828+ < div > child</ div >
829+ </ ListenerProvider > ,
830+ ) ;
831+
832+ await vi . waitFor ( ( ) => expect ( listenMock ) . toHaveBeenCalledTimes ( 1 ) ) ;
833+
834+ const handler = listenMock . mock . calls [ 0 ] ?. [ 0 ] ;
835+ expect ( handler ) . toBeTypeOf ( "function" ) ;
836+
837+ handler ( {
838+ payload : {
839+ type : "micDetected" ,
840+ key : "mic-1" ,
841+ apps : [ { id : "us.zoom.xos" , name : "Zoom" } ] ,
842+ duration_secs : 15 ,
843+ } ,
844+ } ) ;
845+
846+ await vi . waitFor ( ( ) =>
847+ expect ( showNotificationMock ) . toHaveBeenCalledWith (
848+ expect . objectContaining ( {
849+ title : "Are you talking to Artem right now?" ,
850+ source : expect . objectContaining ( {
851+ event_ids : [ "event-1" ] ,
852+ } ) ,
853+ action_label : "Yes" ,
854+ options : null ,
855+ } ) ,
856+ ) ,
857+ ) ;
858+ } ) ;
859+
805860 test ( "detects Microsoft Teams live join links for browser mic notifications" , async ( ) => {
806861 const store = createListenerStore ( ) ;
807862
@@ -902,8 +957,11 @@ describe("ListenerProvider detect events", () => {
902957 expect . objectContaining ( {
903958 source : expect . objectContaining ( {
904959 app_names : [ "Google Meet" ] ,
905- event_ids : [ "event-1" , "event- 2"] ,
960+ event_ids : [ "event-2" ] ,
906961 } ) ,
962+ title : "Are you in Design sync right now?" ,
963+ action_label : "Yes" ,
964+ options : null ,
907965 footer : expect . objectContaining ( {
908966 text : "Ignore Google Meet?" ,
909967 } ) ,
@@ -916,6 +974,62 @@ describe("ListenerProvider detect events", () => {
916974 ) ;
917975 } ) ;
918976
977+ test ( "does not infer browser platform from a different nearby event" , async ( ) => {
978+ const store = createListenerStore ( ) ;
979+
980+ vi . useFakeTimers ( ) ;
981+ vi . setSystemTime ( new Date ( "2026-06-24T02:09:00.000Z" ) ) ;
982+ ( useStoreMock as any ) . mockReturnValue (
983+ mockNearbyEventStoreMany ( [
984+ {
985+ title : "Sales sync" ,
986+ started_at : "2026-06-24T02:09:00.000Z" ,
987+ } ,
988+ {
989+ title : "Design sync" ,
990+ started_at : "2026-06-24T02:10:00.000Z" ,
991+ meeting_link : "https://meet.google.com/abc-defg-hij" ,
992+ } ,
993+ ] ) ,
994+ ) ;
995+
996+ render (
997+ < ListenerProvider store = { store } >
998+ < div > child</ div >
999+ </ ListenerProvider > ,
1000+ ) ;
1001+
1002+ await vi . waitFor ( ( ) => expect ( listenMock ) . toHaveBeenCalledTimes ( 1 ) ) ;
1003+
1004+ const handler = listenMock . mock . calls [ 0 ] ?. [ 0 ] ;
1005+ expect ( handler ) . toBeTypeOf ( "function" ) ;
1006+
1007+ handler ( {
1008+ payload : {
1009+ type : "micDetected" ,
1010+ key : "mic-1" ,
1011+ apps : [ { id : "com.google.Chrome" , name : "Google Chrome" } ] ,
1012+ duration_secs : 15 ,
1013+ } ,
1014+ } ) ;
1015+
1016+ await vi . waitFor ( ( ) =>
1017+ expect ( showNotificationMock ) . toHaveBeenCalledWith (
1018+ expect . objectContaining ( {
1019+ source : expect . objectContaining ( {
1020+ app_names : [ "Google Chrome" ] ,
1021+ event_ids : [ "event-1" ] ,
1022+ } ) ,
1023+ title : "Are you in Sales sync right now?" ,
1024+ footer : expect . objectContaining ( {
1025+ text : "Ignore Google Chrome?" ,
1026+ } ) ,
1027+ icon : { type : "bundle_id" , bundle_id : "com.google.Chrome" } ,
1028+ } ) ,
1029+ ) ,
1030+ ) ;
1031+ } ) ;
1032+
9191033 test ( "does not infer chat platforms from incidental calendar text" , async ( ) => {
9201034 const store = createListenerStore ( ) ;
9211035
@@ -1191,6 +1305,9 @@ describe("ListenerProvider detect events", () => {
11911305 app_ids : [ "at.studio.AsideBrowser" ] ,
11921306 event_ids : [ "event-1" ] ,
11931307 } ) ,
1308+ title : "Are you in Founder call right now?" ,
1309+ action_label : "Yes" ,
1310+ options : null ,
11941311 footer : expect . objectContaining ( {
11951312 text : "Ignore Cal Video?" ,
11961313 icon : {
0 commit comments