@ -14,9 +14,7 @@ import {
TextField ,
InputAdornment ,
Avatar ,
Chip ,
FormControlLabel ,
Switch
Chip
} from '@mui/material' ;
import {
Share ,
@ -27,7 +25,10 @@ import {
GetApp ,
Refresh ,
ArrowBack ,
Groups
Groups ,
CheckCircle ,
Schedule ,
PersonOutline
} from '@mui/icons-material' ;
import { QRCodeSVG } from 'qrcode.react' ;
import { dataService } from '../services/dataService' ;
@ -41,11 +42,11 @@ const InvitationPage = () => {
inviterName? : string ;
relationshipType? : string ;
} > ( { } ) ;
const [ isExistingMember , setIsExistingMember ] = useState ( false ) ;
const [ copySuccess , setCopySuccess ] = useState ( false ) ;
const [ invitationId , setInvitationId ] = useState ( '' ) ;
const [ group , setGroup ] = useState < Group | null > ( null ) ;
const [ isGroupInvite , setIsGroupInvite ] = useState ( false ) ;
const [ inviteeNaoStatus , setInviteeNaoStatus ] = useState < 'member' | 'invited' | 'not_invited' | null > ( null ) ;
const navigate = useNavigate ( ) ;
const [ searchParams ] = useSearchParams ( ) ;
@ -64,17 +65,21 @@ const InvitationPage = () => {
relationshipType : relationshipType || undefined ,
} ) ;
// Auto-detect if invitee is an existing member by checking contacts
// Determine member status from contact data if available
let isExistingMember = false ;
if ( inviteeName ) {
try {
const contacts : Contact [ ] = await dataService . getContacts ( ) ;
const isExistingC ontact = contacts . some ( contact = >
contact . name . toLowerCase ( ) === inviteeName . toLowerCase ( )
const c ontact = contacts . find ( c = >
c . name . toLowerCase ( ) === inviteeName . toLowerCase ( )
) ;
if ( isExistingContact ) {
console . log ( ` Auto-detected ${ inviteeName } as existing member ` ) ;
setIsExistingMember ( true ) ;
if ( contact ) {
isExistingMember = contact . naoStatus === 'member' ;
setInviteeNaoStatus ( contact . naoStatus || 'not_invited' ) ;
console . log ( ` ${ inviteeName } NAO status: ` , contact . naoStatus ) ;
} else {
setInviteeNaoStatus ( 'not_invited' ) ;
}
} catch ( error ) {
console . error ( 'Failed to check contacts:' , error ) ;
@ -202,7 +207,7 @@ const InvitationPage = () => {
}
} ;
const handleNewInvitation = ( ) = > {
const handleNewInvitation = async ( ) = > {
const groupId = searchParams . get ( 'groupId' ) ;
const inviteeName = searchParams . get ( 'inviteeName' ) ;
const inviterName = searchParams . get ( 'inviterName' ) ;
@ -211,6 +216,26 @@ const InvitationPage = () => {
const id = Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) ;
setInvitationId ( id ) ;
// Determine member status from contact data if available
let isExistingMember = false ;
if ( inviteeName ) {
try {
const contacts : Contact [ ] = await dataService . getContacts ( ) ;
const contact = contacts . find ( c = >
c . name . toLowerCase ( ) === inviteeName . toLowerCase ( )
) ;
if ( contact ) {
isExistingMember = contact . naoStatus === 'member' ;
setInviteeNaoStatus ( contact . naoStatus || 'not_invited' ) ;
} else {
setInviteeNaoStatus ( 'not_invited' ) ;
}
} catch ( error ) {
console . error ( 'Failed to check contacts:' , error ) ;
}
}
// Build URL with personalized parameters
const urlParams = new URLSearchParams ( {
invite : id ,
@ -365,47 +390,41 @@ const InvitationPage = () => {
Invitation ID : { invitationId }
< / Typography >
{ /* Existing Member Toggle */ }
< Box sx = { { mb : 2 } } >
< FormControlLabel
control = {
< Switch
checked = { isExistingMember }
onChange = { ( e ) = > {
setIsExistingMember ( e . target . checked ) ;
// Regenerate URL when toggle changes
const id = Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) ;
setInvitationId ( id ) ;
const groupId = searchParams . get ( 'groupId' ) ;
const inviteeName = searchParams . get ( 'inviteeName' ) ;
const inviterName = searchParams . get ( 'inviterName' ) ;
const relationshipType = searchParams . get ( 'relationshipType' ) ;
const urlParams = new URLSearchParams ( {
invite : id ,
. . . ( groupId && { groupId } ) ,
. . . ( inviteeName && { inviteeName } ) ,
. . . ( inviterName && { inviterName } ) ,
. . . ( relationshipType && { relationshipType } ) ,
. . . ( e . target . checked && { existingMember : 'true' } ) ,
} ) ;
const url = ` ${ window . location . origin } /onboarding? ${ urlParams . toString ( ) } ` ;
setInvitationUrl ( url ) ;
} }
color = "primary"
/ >
}
label = "Recipient is already a NAO member"
sx = { { alignItems : 'flex-start' } }
/ >
< Typography variant = "caption" color = "text.secondary" sx = { { display : 'block' , mt : 0.5 } } >
{ isExistingMember
? "They'll choose how to connect with this group using their existing profile"
: "They'll need to create a new NAO account first"
}
{ /* NAO Status Indicator */ }
{ personalizedInvite . inviteeName && inviteeNaoStatus && (
< Box sx = { { mb : 2 , p : 1.5 , borderRadius : 2 , backgroundColor : 'grey.50' , border : 1 , borderColor : 'divider' } } >
< Typography variant = "body2" sx = { { fontWeight : 500 , mb : 0.5 } } >
Recipient Status :
< / Typography >
< Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
{ inviteeNaoStatus === 'member' && (
< >
< CheckCircle sx = { { fontSize : 16 , color : 'success.main' } } / >
< Typography variant = "body2" color = "success.main" >
< strong > { personalizedInvite . inviteeName } < / strong > is already a NAO member - they ' ll choose how to connect with this group
< / Typography >
< / >
) }
{ inviteeNaoStatus === 'invited' && (
< >
< Schedule sx = { { fontSize : 16 , color : 'warning.main' } } / >
< Typography variant = "body2" color = "warning.main" >
< strong > { personalizedInvite . inviteeName } < / strong > has been invited to NAO but hasn ' t joined yet
< / Typography >
< / >
) }
{ inviteeNaoStatus === 'not_invited' && (
< >
< PersonOutline sx = { { fontSize : 16 , color : 'text.secondary' } } / >
< Typography variant = "body2" color = "text.secondary" >
< strong > { personalizedInvite . inviteeName } < / strong > will need to create a new NAO account
< / Typography >
< / >
) }
< / Box >
< / Box >
) }
< Divider sx = { { my : 2 } } / >