@@ -370,49 +370,128 @@ export const SettingsGeneral: Component = () => {
370370 </ div >
371371 )
372372
373- const NotificationsSection = ( ) => (
374- < div class = "flex flex-col gap-1" >
375- < h3 class = "text-14-medium text-text-strong pb-2" > { language . t ( "settings.general.section.notifications" ) } </ h3 >
376-
377- < SettingsList >
378- < SettingsRow
379- title = { language . t ( "settings.general.notifications.agent.title" ) }
380- description = { language . t ( "settings.general.notifications.agent.description" ) }
381- >
382- < div data-action = "settings-notifications-agent" >
383- < Switch
384- checked = { settings . notifications . agent ( ) }
385- onChange = { ( checked ) => settings . notifications . setAgent ( checked ) }
386- />
387- </ div >
388- </ SettingsRow >
389-
390- < SettingsRow
391- title = { language . t ( "settings.general.notifications.permissions.title" ) }
392- description = { language . t ( "settings.general.notifications.permissions.description" ) }
393- >
394- < div data-action = "settings-notifications-permissions" >
395- < Switch
396- checked = { settings . notifications . permissions ( ) }
397- onChange = { ( checked ) => settings . notifications . setPermissions ( checked ) }
398- />
399- </ div >
400- </ SettingsRow >
373+ const NotificationsSection = ( ) => {
374+ const platform = usePlatform ( )
375+
376+ const [ pushState , { refetch } ] = createResource (
377+ ( ) => platform . platform === "ios" ,
378+ async ( isIOS ) => {
379+ if ( ! isIOS ) return null
380+ try {
381+ return await platform . getPushState ?.( )
382+ } catch {
383+ return null
384+ }
385+ } ,
386+ )
387+
388+ const permissionStatus = createMemo ( ( ) => {
389+ const state = pushState ( )
390+ if ( ! state ) return null
391+ const permission = state . permission
392+ const allowed = state . allowed ?? false
393+
394+ if ( permission === "authorized" )
395+ return { text : language . t ( "settings.general.notifications.status.authorized" ) , color : "text-green-600" }
396+ if ( permission === "denied" )
397+ return { text : language . t ( "settings.general.notifications.status.denied" ) , color : "text-red-600" }
398+ if ( permission === "not-determined" )
399+ return { text : language . t ( "settings.general.notifications.status.notDetermined" ) , color : "text-yellow-600" }
400+ return allowed
401+ ? { text : language . t ( "settings.general.notifications.status.authorized" ) , color : "text-green-600" }
402+ : { text : language . t ( "settings.general.notifications.status.notAuthorized" ) , color : "text-text-weak" }
403+ } )
401404
402- < SettingsRow
403- title = { language . t ( "settings.general.notifications.errors.title" ) }
404- description = { language . t ( "settings.general.notifications.errors.description" ) }
405- >
406- < div data-action = "settings-notifications-errors" >
407- < Switch
408- checked = { settings . notifications . errors ( ) }
409- onChange = { ( checked ) => settings . notifications . setErrors ( checked ) }
410- />
411- </ div >
412- </ SettingsRow >
413- </ SettingsList >
414- </ div >
415- )
405+ const handleRequestPermission = async ( ) => {
406+ try {
407+ await platform . requestPushPermission ?.( )
408+ refetch ( )
409+ showToast ( {
410+ variant : "success" ,
411+ title : language . t ( "settings.general.notifications.permissionRequested" ) ,
412+ } )
413+ } catch ( err ) {
414+ showToast ( {
415+ variant : "error" ,
416+ title : language . t ( "common.requestFailed" ) ,
417+ description : String ( err ) ,
418+ } )
419+ }
420+ }
421+
422+ const handleOpenSettings = ( ) => {
423+ platform . openSystemSettings ?.( )
424+ }
425+
426+ return (
427+ < div class = "flex flex-col gap-1" >
428+ < h3 class = "text-14-medium text-text-strong pb-2" > { language . t ( "settings.general.section.notifications" ) } </ h3 >
429+
430+ < SettingsList >
431+ < Show when = { platform . platform === "ios" } >
432+ < SettingsRow
433+ title = { language . t ( "settings.general.notifications.systemPermission.title" ) }
434+ description = { language . t ( "settings.general.notifications.systemPermission.description" ) }
435+ >
436+ < div class = "flex items-center gap-2" >
437+ < Show when = { permissionStatus ( ) } >
438+ { ( status ) => < span class = { `text-12-medium ${ status ( ) . color } ` } > { status ( ) . text } </ span > }
439+ </ Show >
440+ < Show
441+ when = { permissionStatus ( ) ?. text === language . t ( "settings.general.notifications.status.notDetermined" ) }
442+ >
443+ < Button size = "small" onClick = { handleRequestPermission } >
444+ { language . t ( "settings.general.notifications.requestPermission" ) }
445+ </ Button >
446+ </ Show >
447+ < Show when = { permissionStatus ( ) ?. text === language . t ( "settings.general.notifications.status.denied" ) } >
448+ < Button size = "small" onClick = { handleOpenSettings } >
449+ { language . t ( "settings.general.notifications.openSettings" ) }
450+ </ Button >
451+ </ Show >
452+ </ div >
453+ </ SettingsRow >
454+ </ Show >
455+
456+ < SettingsRow
457+ title = { language . t ( "settings.general.notifications.agent.title" ) }
458+ description = { language . t ( "settings.general.notifications.agent.description" ) }
459+ >
460+ < div data-action = "settings-notifications-agent" >
461+ < Switch
462+ checked = { settings . notifications . agent ( ) }
463+ onChange = { ( checked ) => settings . notifications . setAgent ( checked ) }
464+ />
465+ </ div >
466+ </ SettingsRow >
467+
468+ < SettingsRow
469+ title = { language . t ( "settings.general.notifications.permissions.title" ) }
470+ description = { language . t ( "settings.general.notifications.permissions.description" ) }
471+ >
472+ < div data-action = "settings-notifications-permissions" >
473+ < Switch
474+ checked = { settings . notifications . permissions ( ) }
475+ onChange = { ( checked ) => settings . notifications . setPermissions ( checked ) }
476+ />
477+ </ div >
478+ </ SettingsRow >
479+
480+ < SettingsRow
481+ title = { language . t ( "settings.general.notifications.errors.title" ) }
482+ description = { language . t ( "settings.general.notifications.errors.description" ) }
483+ >
484+ < div data-action = "settings-notifications-errors" >
485+ < Switch
486+ checked = { settings . notifications . errors ( ) }
487+ onChange = { ( checked ) => settings . notifications . setErrors ( checked ) }
488+ />
489+ </ div >
490+ </ SettingsRow >
491+ </ SettingsList >
492+ </ div >
493+ )
494+ }
416495
417496 const SoundsSection = ( ) => (
418497 < div class = "flex flex-col gap-1" >
0 commit comments