You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

566 lines
20 KiB

<!--
HelpNotificationsView.vue - Push Notification Help & Testing Component
User support component that provides comprehensive help and testing functionality
for push notifications. Critical for users experiencing notification issues.
Key Features:
- Push notification testing with multiple test scenarios
- Comprehensive troubleshooting guide for notification issues
- System permission checks for various platforms and browsers
- Web push subscription management and diagnostics
- Direct device testing without push server dependency
User Experience Impact:
- High priority for users having notification issues
- Primary troubleshooting resource for notification problems
- Platform-specific guidance for iOS, Android, Mac, Windows
- Technical diagnostic tools for developers and support
Database Operations:
- Settings updates for notification preferences via PlatformServiceMixin
- Simple key-value updates for notification configuration
- No complex queries or data relationships
Security Considerations:
- No sensitive data exposure in notifications or logs
- Safe diagnostic information display
- Secure push subscription handling
@author Matthew Raymer
-->
<template>
<QuickNav />
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="goBack()"
>
<font-awesome icon="chevron-left" class="fa-fw"></font-awesome>
</h1>
</div>
<!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Notification Help
</h1>
</div>
<!-- eslint-disable prettier/prettier -->
<div>
<p>Here are ways to test notifications and get them working.</p>
<h2 class="text-xl font-semibold mt-4">Full Test</h2>
<div>
<p>
If this works then you're all set.
<button
:class="primaryTestButtonClass"
@click="sendTestWebPushMessage(true)"
>
Send Yourself a Test Web Push Message (Through Push Server but
Skipping Client Filter)
</button>
</p>
</div>
<h2 class="text-xl font-semibold mt-4">Android Users</h2>
<div>
<p>
Note that you may not receive notifications when the app is in the
background. When you're done working, close the app, and then you'll
get the reminder notifications.
</p>
</div>
<h2 class="text-xl font-semibold mt-4">
If this app doesn't support notifications...
<!-- Note that that exact verbiage shows in a message elsewhere. -->
</h2>
<div>
<p>
To be notified of interesting updates, install this app on your device
(as opposed to using it inside the browser app). In Chrome, it may prompt
you, and you can also look for the "Install" command in the browser
settings.
</p>
</div>
<h2 class="text-xl font-semibold mt-4">
If you must enable notifications...
<!-- Note that that exact verbiage shows in a message elsewhere. -->
</h2>
<div>
<p>
<button class="text-blue-500" @click="showNotificationChoice()">
Click here.
</button>
<PushNotificationPermission ref="pushNotificationPermission" />
</p>
</div>
<h2 class="text-xl font-semibold mt-4">
If you're waiting for system initialization...
<!-- Note that that exact verbiage shows in a message elsewhere. -->
</h2>
<div>
<p>
... and it never stops, then there is a problem with the underlying
service worker or push server mechanism in your browser. Your best bet
is to follow the "Reinstall" steps below or use a different browser.
</p>
</div>
<h2 class="text-xl font-semibold mt-4">Check App Permissions</h2>
<div>
<p>
In Apple iOS, check "Settings" -> "Notifications", look for the Time
Safari app (or the browser you're using), and make sure notifications
are enabled.
</p>
<p>
In Android, hold on to the app icon, then select "App Info", then
"Notifications" and make sure they're enabled. If it's still a problem
then go further:
</p>
<p>
If you installed the app with Chrome, make sure there are no other
tabs with it open. Here are some ways to clear caches that can mess
things up (and note that this clears out data from the installed app
-- which is good to do while the app is installed):
</p>
<ul>
<li class="list-disc ml-4">
Go to Chrome "App Info", then "Storage & Cache" and "Clear Storage".
</li>
<li class="list-disc ml-4">
Go to Chrome "Settings", then "Privacy and Security" and "Clear
"Clear browsing data", then "Cookies and site data". Make sure the
"Time Range" at the top shows "All time".
</li>
</ul>
<p>
On a Mac, go to "Settings" and check "Notifications".
<img
src="../assets/help/mac-installed-app-settings.png"
alt="Mac app settings"
class="ml-4"
/>
</p>
</div>
<h2 class="text-xl font-semibold mt-4">Check Browser Permissions</h2>
<div>
<p>In Apple iOS, check Settings -> Notifications.</p>
<p>In Android, check Settings -> Notifications.</p>
You can find more details about compatibility
<a
href="https://developer.mozilla.org/en-US/docs/Web/API/Push_API#browser_compatibility"
class="text-blue-500"
target="_blank"
>
here <font-awesome icon="arrow-up-right-from-square" class="fa-fw" />
</a>
</div>
<h2 class="text-xl font-semibold mt-4">
Check Operating System (OS) Permissions
</h2>
<div class="px-2">
<div>
<h3 class="text-lg font-semibold">Mobile Phone - Apple iOS</h3>
<div>
Notifications require iOS 16.4 or higher. To check your iOS version,
go to Settings > General > About > Software Version.
</div>
<h3 class="text-lg font-semibold">Mobile Phone - Google Android</h3>
<div>
We recommend Chrome. It must be version 42 or higher. Check your
version under Settings -> About Chrome.
</div>
<h3 class="text-lg font-semibold">Desktop - Mac</h3>
<div>
<span>
See "System Settings" -> "Notifications" and make sure it is
enabled for the browser you're using. Note that these
notifications require Mac OS 13; see your macOS version under
Apple -> "About This Mac".
</span>
</div>
<h3 class="text-lg font-semibold">Desktop - Windows</h3>
In Windows, check "Settings" -> "Notifications".
<img
src="../assets/help/windows-system-enable-notifications.png"
alt="Windows system settings"
class="ml-4"
/>
</div>
<div>
You can find more details about compatibility
<a
href="https://developer.mozilla.org/en-US/docs/Web/API/Push_API#browser_compatibility"
class="text-blue-500"
target="_blank"
>
here <font-awesome icon="arrow-up-right-from-square" class="fa-fw" />
</a>
</div>
</div>
<h2 class="text-xl font-semibold mt-4">Reinstall</h2>
<div>
<p>
If all else fails, it's best to start over.
</p>
<p>
Of course, you'll want to back up all your data first -- all seeds as
well as the contacts & settings -- on the Profile
<font-awesome icon="circle-user" /> page.
</p>
<p>
Here are instructions to uninstall the app and clear out caches and storage.
Note that you should first ensure check that the browser tabs with Time Safari are closed.
(If any are open then that will interfere with your refresh.)
</p>
<ul class="ml-4 list-disc">
<li>
Clear cache.
<ul>
<li>
In mobile, look for the browser app settings. This is true even
for an installed app: go to the browser which you used to
initially visit timesafari.app, because those settings affect
the app. Look for "Delete browsing data" in the "Settings",
under "Privacy and Security".
</li>
<li>
In Chrome, go to `chrome://settings/cookies` and "all site data
and permissions" for timesafari.app; in Firefox, go to
`about:preferences` and search for "cache" then "Manage Data"
for timesafari.app. Also manually remove the IndexedDB data if
the DBs still show.)
</li>
</ul>
</li>
<li>
Clear notification permission. (In Chrome, go to
`chrome://settings/content/notifications`; in Firefox, go to
`about:preferences` and search for "notifications".)
</li>
<li>
Unregister service worker. (In Chrome, go to
`chrome://serviceworker-internals/`; in Firefox, go to
`about:serviceworkers`.)
</li>
<li>
Clear "Cache Storage". (In Chrome, in dev tools under "Application";
in Firefox, in dev tools under "Storage".)
</li>
</ul>
<p>Then reinstall the app.</p>
</div>
<h2 class="text-xl font-semibold mt-4">Tests</h2>
<button
:class="testButtonClass"
@click="showTestNotification()"
>
Send Test Notification Directly to Device (Not Through Push Server)
</button>
<p>
If that didn't show a notification on your device, the problem is that
your browser or your operating system are not allowing notifications
through. See "Check App Permissions" and "Check Browser Permissions" and
"Check Operating System (OS) Permissions" above.
</p>
<button
:class="testButtonClass"
@click="alertWebPushSubscription()"
>
Show Web Push Subscription Info
</button>
<p>
If that showed "null" then the notification is not active.
<button class="text-blue-500" @click="showNotificationChoice()">
Click here.
</button>
</p>
<button
:class="testButtonClass"
@click="sendTestWebPushMessage(true)"
>
Send Yourself a Test Web Push Message (Through Push Server but Skipping
Client Filter)
</button>
<p>
If that didn't show a notification on your device, there is a problem
getting to the push server. Disable notifications and then enable them
again.
</p>
<button
:class="testButtonClass"
@click="sendTestWebPushMessage()"
>
Send Yourself a Test Web Push Message (Through Push Server and Client
Filter)
</button>
<p>
If you don't see a message, it could be that there is nothing new for
you to see. If the previous test worked, then things should work fine.
If you notice a full 24 hours where you get no notification and you know
that there are new items that should show, gather as many details as
possible and go to the bottom of
<router-link to="help" class="text-blue-500"> this page </router-link>
for ways to contact us.
</p>
</div>
<!-- eslint-enable -->
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import { DIRECT_PUSH_TITLE, sendTestThroughPushServer } from "../libs/util";
import PushNotificationPermission from "../components/PushNotificationPermission.vue";
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "../utils/notify";
import {
NOTIFY_PUSH_NOT_SUBSCRIBED,
NOTIFY_TEST_WEB_PUSH_SUCCESS,
NOTIFY_TEST_WEB_PUSH_ERROR,
NOTIFY_TEST_NOTIFICATION_SUCCESS,
NOTIFY_TEST_NOTIFICATION_ERROR,
} from "../constants/notifications";
import { Router } from "vue-router";
import { logger } from "../utils/logger";
/**
* HelpNotificationsView Component
*
* User support component that provides comprehensive help and testing functionality
* for push notifications. Critical for users experiencing notification issues.
*
* Key features:
* - Push notification testing with multiple test scenarios
* - Comprehensive troubleshooting guide for notification issues
* - System permission checks for various platforms and browsers
* - Web push subscription management and diagnostics
* - Direct device testing without push server dependency
*
* User Experience Impact:
* - High priority for users having notification issues
* - Primary troubleshooting resource for notification problems
* - Platform-specific guidance for iOS, Android, Mac, Windows
* - Technical diagnostic tools for developers and support
*
* Database Operations:
* - Settings updates for notification preferences via PlatformServiceMixin
* - Simple key-value updates for notification configuration
* - No complex queries or data relationships
*
* Security Features:
* - No sensitive data exposure in notifications or logs
* - Safe diagnostic information display
* - Secure push subscription handling
* - Proper error handling without data leakage
*
* @author Matthew Raymer
*/
@Component({
components: { PushNotificationPermission, QuickNav },
mixins: [PlatformServiceMixin],
})
export default class HelpNotificationsView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
$router!: Router;
subscriptionJSON?: PushSubscriptionJSON;
notifyingReminder = false;
notifyingReminderMessage = "";
notifyingReminderTime = "";
// Notification helper system
notify = createNotifyHelpers(this.$notify);
/**
* Computed property for consistent button styling
* Used for all test buttons in the notification help interface
*/
get buttonClass(): string {
return "block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md";
}
/**
* Computed property for test button styling with margins
* Used for test buttons in the Tests section
*/
get testButtonClass(): string {
return this.buttonClass + " mt-4 mb-2";
}
/**
* Computed property for primary test button styling
* Used for the main test button with bottom margin
*/
get primaryTestButtonClass(): string {
return this.buttonClass + " mb-2";
}
/**
* Vue mounted lifecycle hook
*
* Initializes the component by setting up push subscription information.
* Retrieves the current push subscription from the service worker and stores
* it for display and testing purposes.
*
* Handles errors gracefully with proper logging without exposing sensitive data.
*/
async mounted() {
try {
const registration = await navigator.serviceWorker?.ready;
const fullSub = await registration?.pushManager.getSubscription();
this.subscriptionJSON = fullSub?.toJSON();
} catch (error) {
logger.error("Mount error:", error);
}
}
/**
* Navigates back to the previous page
* Provides consistent navigation behavior for the back button
*/
goBack(): void {
this.$router.back();
}
/**
* Displays web push subscription information
*
* Shows the current push subscription details to the user for diagnostic purposes.
* Useful for troubleshooting push notification issues and verifying subscription status.
*/
alertWebPushSubscription() {
alert(JSON.stringify(this.subscriptionJSON));
}
/**
* Sends test web push message through push server
*
* Sends a test notification through the push server to verify the complete
* notification pipeline. Can skip client-side filtering for testing purposes.
*
* @param skipFilter - Whether to skip client-side message filtering
*/
async sendTestWebPushMessage(skipFilter: boolean = false) {
if (!this.subscriptionJSON) {
this.notify.error(NOTIFY_PUSH_NOT_SUBSCRIBED.message, TIMEOUTS.STANDARD);
return;
}
try {
await sendTestThroughPushServer(this.subscriptionJSON, skipFilter);
this.notify.success(
this.getTestWebPushSuccessMessage(skipFilter),
TIMEOUTS.STANDARD,
);
} catch (error) {
logger.error("Got an error sending test notification:", error);
this.notify.error(NOTIFY_TEST_WEB_PUSH_ERROR.message, TIMEOUTS.STANDARD);
}
}
/**
* Shows test notification directly to device
*
* Displays a test notification directly through the service worker without
* using the push server. Useful for testing local notification capabilities.
*/
showTestNotification() {
const TEST_NOTIFICATION_TITLE = "It Worked";
navigator.serviceWorker?.ready
.then((registration) => {
return registration.showNotification(TEST_NOTIFICATION_TITLE, {
body: "This is your test notification.",
});
})
.then(() => {
this.notify.success(
this.getTestNotificationSuccessMessage(TEST_NOTIFICATION_TITLE),
TIMEOUTS.STANDARD,
);
})
.catch((error) => {
logger.error("Got a notification error:", error);
this.notify.error(
NOTIFY_TEST_NOTIFICATION_ERROR.message,
TIMEOUTS.STANDARD,
);
});
}
/**
* Shows notification permission choice dialog
*
* Opens the notification permission dialog to allow users to enable
* notifications. Updates notification settings upon successful permission grant.
*/
showNotificationChoice() {
(this.$refs.pushNotificationPermission as PushNotificationPermission).open(
DIRECT_PUSH_TITLE,
async (success: boolean, timeText: string, message?: string) => {
if (success) {
await this.$updateSettings({
notifyingReminderMessage: message,
notifyingReminderTime: timeText,
});
this.notifyingReminder = true;
this.notifyingReminderMessage = message || "";
this.notifyingReminderTime = timeText;
}
},
);
}
/**
* Generates test web push success message
*
* Creates a dynamic success message based on whether client filtering is skipped.
*
* @param skipFilter - Whether client-side message filtering was skipped
* @returns Formatted success message string
*/
private getTestWebPushSuccessMessage(skipFilter: boolean): string {
return (
NOTIFY_TEST_WEB_PUSH_SUCCESS.message +
(skipFilter ? "." : " if there are new items in your feed.")
);
}
/**
* Generates test notification success message
*
* Creates a dynamic success message with the notification title inserted.
*
* @param title - The title of the test notification
* @returns Formatted success message string
*/
private getTestNotificationSuccessMessage(title: string): string {
return NOTIFY_TEST_NOTIFICATION_SUCCESS.message.replace("{title}", title);
}
}
</script>