Browse Source

Extract notification section into reusable component

- Created NotificationSection.vue with complete notification functionality
- Updated AccountViewView to use new component via props
- Removed notification methods from AccountViewView
- Fixed FontAwesome import to use FontAwesomeIcon
- Cleaned up unused imports and dependencies
pull/150/head
Matthew Raymer 3 weeks ago
parent
commit
0493f4f061
  1. 212
      src/components/NotificationSection.vue
  2. 182
      src/views/AccountViewView.vue

212
src/components/NotificationSection.vue

@ -0,0 +1,212 @@
<template>
<section
v-if="isRegistered"
id="sectionNotifications"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
aria-labelledby="notificationsHeading"
>
<h2 id="notificationsHeading" class="mb-2 font-bold">Notifications</h2>
<div class="flex items-center justify-between">
<div>
Reminder Notification
<button
class="text-slate-400 fa-fw cursor-pointer"
aria-label="Learn more about reminder notifications"
@click.stop="showReminderNotificationInfo"
>
<font-awesome-icon
icon="question-circle"
aria-hidden="true"
/>
</button>
</div>
<div
class="relative ml-2 cursor-pointer"
role="switch"
:aria-checked="notifyingReminder"
aria-label="Toggle reminder notifications"
tabindex="0"
@click="showReminderNotificationChoice()"
>
<!-- input -->
<input v-model="notifyingReminder" type="checkbox" class="sr-only" />
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</div>
<div v-if="notifyingReminder" class="w-full flex justify-between">
<span class="ml-8 mr-8">Message: "{{ notifyingReminderMessage }}"</span>
<span>{{ notifyingReminderTime.replace(" ", "&nbsp;") }}</span>
</div>
<div class="mt-2 flex items-center justify-between">
<!-- label -->
<div>
New Activity Notification
<font-awesome-icon
icon="question-circle"
class="text-slate-400 fa-fw cursor-pointer"
@click.stop="showNewActivityNotificationInfo"
/>
</div>
<!-- toggle -->
<div
class="relative ml-2 cursor-pointer"
@click="showNewActivityNotificationChoice()"
>
<!-- input -->
<input v-model="notifyingNewActivity" type="checkbox" class="sr-only" />
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</div>
<div v-if="notifyingNewActivityTime" class="w-full text-right">
{{ notifyingNewActivityTime.replace(" ", "&nbsp;") }}
</div>
<div class="mt-2 text-center">
<router-link class="text-sm text-blue-500" to="/help-notifications">
Troubleshoot your notifications&hellip;
</router-link>
</div>
</section>
<PushNotificationPermission ref="pushNotificationPermission" />
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import PushNotificationPermission from "./PushNotificationPermission.vue";
import { createNotifyHelpers } from "@/utils/notify";
import { ACCOUNT_VIEW_CONSTANTS } from "@/constants/accountView";
import { DAILY_CHECK_TITLE, DIRECT_PUSH_TITLE } from "@/libs/util";
import { NotificationIface } from "@/constants/app";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
/**
* NotificationSection.vue - Extracted notification management component
*
* This component handles all notification-related functionality including:
* - Reminder notifications with custom messages
* - New activity notifications
* - Notification permission management
* - Help and troubleshooting links
*
* @author Matthew Raymer
* @component NotificationSection
* @vue-facing-decorator
*/
@Component({
components: {
FontAwesomeIcon,
PushNotificationPermission,
},
mixins: [PlatformServiceMixin],
})
export default class NotificationSection extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
$router!: Router;
// Props
isRegistered: boolean = false;
notifyingNewActivity: boolean = false;
notifyingNewActivityTime: string = "";
notifyingReminder: boolean = false;
notifyingReminderMessage: string = "";
notifyingReminderTime: string = "";
private notify!: ReturnType<typeof createNotifyHelpers>;
created() {
this.notify = createNotifyHelpers(this.$notify);
}
async showNewActivityNotificationInfo(): Promise<void> {
this.notify.confirm(
ACCOUNT_VIEW_CONSTANTS.NOTIFICATIONS.NEW_ACTIVITY_INFO,
async () => {
await (this.$router as Router).push({
name: "help-notification-types",
});
},
);
}
async showNewActivityNotificationChoice(): Promise<void> {
if (!this.notifyingNewActivity) {
(
this.$refs.pushNotificationPermission as PushNotificationPermission
).open(DAILY_CHECK_TITLE, async (success: boolean, timeText: string) => {
if (success) {
await this.$saveSettings({
notifyingNewActivityTime: timeText,
});
this.notifyingNewActivity = true;
this.notifyingNewActivityTime = timeText;
}
});
} else {
this.notify.notificationOff(DAILY_CHECK_TITLE, async (success) => {
if (success) {
await this.$saveSettings({
notifyingNewActivityTime: "",
});
this.notifyingNewActivity = false;
this.notifyingNewActivityTime = "";
}
});
}
}
async showReminderNotificationInfo(): Promise<void> {
this.notify.confirm(
ACCOUNT_VIEW_CONSTANTS.NOTIFICATIONS.REMINDER_INFO,
async () => {
await (this.$router as Router).push({
name: "help-notification-types",
});
},
);
}
async showReminderNotificationChoice(): Promise<void> {
if (!this.notifyingReminder) {
(
this.$refs.pushNotificationPermission as PushNotificationPermission
).open(
DIRECT_PUSH_TITLE,
async (success: boolean, timeText: string, message?: string) => {
if (success) {
await this.$saveSettings({
notifyingReminderMessage: message,
notifyingReminderTime: timeText,
});
this.notifyingReminder = true;
this.notifyingReminderMessage = message || "";
this.notifyingReminderTime = timeText;
}
},
);
} else {
this.notify.notificationOff(DIRECT_PUSH_TITLE, async (success) => {
if (success) {
await this.$saveSettings({
notifyingReminderMessage: "",
notifyingReminderTime: "",
});
this.notifyingReminder = false;
this.notifyingReminderMessage = "";
this.notifyingReminderTime = "";
}
});
}
}
}
</script>

182
src/views/AccountViewView.vue

@ -60,88 +60,14 @@
@share-info="onShareInfo" @share-info="onShareInfo"
/> />
<section <NotificationSection
v-if="isRegistered" :is-registered="isRegistered"
id="sectionNotifications" :notifying-new-activity="notifyingNewActivity"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8" :notifying-new-activity-time="notifyingNewActivityTime"
aria-labelledby="notificationsHeading" :notifying-reminder="notifyingReminder"
> :notifying-reminder-message="notifyingReminderMessage"
<h2 id="notificationsHeading" class="mb-2 font-bold">Notifications</h2> :notifying-reminder-time="notifyingReminderTime"
<div class="flex items-center justify-between"> />
<div>
Reminder Notification
<button
class="text-slate-400 fa-fw cursor-pointer"
aria-label="Learn more about reminder notifications"
@click.stop="showReminderNotificationInfo"
>
<font-awesome
icon="question-circle"
aria-hidden="true"
></font-awesome>
</button>
</div>
<div
class="relative ml-2 cursor-pointer"
role="switch"
:aria-checked="notifyingReminder"
aria-label="Toggle reminder notifications"
tabindex="0"
@click="showReminderNotificationChoice()"
>
<!-- input -->
<input v-model="notifyingReminder" type="checkbox" class="sr-only" />
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</div>
<div v-if="notifyingReminder" class="w-full flex justify-between">
<span class="ml-8 mr-8">Message: "{{ notifyingReminderMessage }}"</span>
<span>{{ notifyingReminderTime.replace(" ", "&nbsp;") }}</span>
</div>
<div class="mt-2 flex items-center justify-between">
<!-- label -->
<div>
New Activity Notification
<font-awesome
icon="question-circle"
class="text-slate-400 fa-fw cursor-pointer"
@click.stop="showNewActivityNotificationInfo"
/>
</div>
<!-- toggle -->
<div
class="relative ml-2 cursor-pointer"
@click="showNewActivityNotificationChoice()"
>
<!-- input -->
<input
v-model="notifyingNewActivity"
type="checkbox"
class="sr-only"
/>
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</div>
<div v-if="notifyingNewActivityTime" class="w-full text-right">
{{ notifyingNewActivityTime.replace(" ", "&nbsp;") }}
</div>
<div class="mt-2 text-center">
<router-link class="text-sm text-blue-500" to="/help-notifications">
Troubleshoot your notifications&hellip;
</router-link>
</div>
</section>
<PushNotificationPermission ref="pushNotificationPermission" />
<LocationSearchSection :search-box="searchBox" /> <LocationSearchSection :search-box="searchBox" />
@ -759,12 +685,13 @@ import { Capacitor } from "@capacitor/core";
import EntityIcon from "../components/EntityIcon.vue"; import EntityIcon from "../components/EntityIcon.vue";
import ImageMethodDialog from "../components/ImageMethodDialog.vue"; import ImageMethodDialog from "../components/ImageMethodDialog.vue";
import PushNotificationPermission from "../components/PushNotificationPermission.vue";
import QuickNav from "../components/QuickNav.vue"; import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue"; import TopMessage from "../components/TopMessage.vue";
import UserNameDialog from "../components/UserNameDialog.vue"; import UserNameDialog from "../components/UserNameDialog.vue";
import DataExportSection from "../components/DataExportSection.vue"; import DataExportSection from "../components/DataExportSection.vue";
import IdentitySection from "@/components/IdentitySection.vue"; import IdentitySection from "@/components/IdentitySection.vue";
import NotificationSection from "@/components/NotificationSection.vue";
import RegistrationNotice from "@/components/RegistrationNotice.vue"; import RegistrationNotice from "@/components/RegistrationNotice.vue";
import LocationSearchSection from "@/components/LocationSearchSection.vue"; import LocationSearchSection from "@/components/LocationSearchSection.vue";
import UsageLimitsSection from "@/components/UsageLimitsSection.vue"; import UsageLimitsSection from "@/components/UsageLimitsSection.vue";
@ -790,11 +717,7 @@ import {
getHeaders, getHeaders,
tokenExpiryTimeDescription, tokenExpiryTimeDescription,
} from "../libs/endorserServer"; } from "../libs/endorserServer";
import { import { retrieveAccountMetadata } from "../libs/util";
DAILY_CHECK_TITLE,
DIRECT_PUSH_TITLE,
retrieveAccountMetadata,
} from "../libs/util";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin"; import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify"; import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
@ -823,7 +746,7 @@ interface UserNameDialogRef {
LMap, LMap,
LMarker, LMarker,
LTileLayer, LTileLayer,
PushNotificationPermission, NotificationSection,
QuickNav, QuickNav,
TopMessage, TopMessage,
UserNameDialog, UserNameDialog,
@ -1102,87 +1025,6 @@ export default class AccountViewView extends Vue {
} }
} }
async showNewActivityNotificationInfo(): Promise<void> {
this.notify.confirm(
ACCOUNT_VIEW_CONSTANTS.NOTIFICATIONS.NEW_ACTIVITY_INFO,
async () => {
await (this.$router as Router).push({
name: "help-notification-types",
});
},
);
}
async showNewActivityNotificationChoice(): Promise<void> {
if (!this.notifyingNewActivity) {
(
this.$refs.pushNotificationPermission as PushNotificationPermission
).open(DAILY_CHECK_TITLE, async (success: boolean, timeText: string) => {
if (success) {
await this.$saveSettings({
notifyingNewActivityTime: timeText,
});
this.notifyingNewActivity = true;
this.notifyingNewActivityTime = timeText;
}
});
} else {
this.notify.notificationOff(DAILY_CHECK_TITLE, async (success) => {
if (success) {
await this.$saveSettings({
notifyingNewActivityTime: "",
});
this.notifyingNewActivity = false;
this.notifyingNewActivityTime = "";
}
});
}
}
async showReminderNotificationInfo(): Promise<void> {
this.notify.confirm(
ACCOUNT_VIEW_CONSTANTS.NOTIFICATIONS.REMINDER_INFO,
async () => {
await (this.$router as Router).push({
name: "help-notification-types",
});
},
);
}
async showReminderNotificationChoice(): Promise<void> {
if (!this.notifyingReminder) {
(
this.$refs.pushNotificationPermission as PushNotificationPermission
).open(
DIRECT_PUSH_TITLE,
async (success: boolean, timeText: string, message?: string) => {
if (success) {
await this.$saveSettings({
notifyingReminderMessage: message,
notifyingReminderTime: timeText,
});
this.notifyingReminder = true;
this.notifyingReminderMessage = message || "";
this.notifyingReminderTime = timeText;
}
},
);
} else {
this.notify.notificationOff(DIRECT_PUSH_TITLE, async (success) => {
if (success) {
await this.$saveSettings({
notifyingReminderMessage: "",
notifyingReminderTime: "",
});
this.notifyingReminder = false;
this.notifyingReminderMessage = "";
this.notifyingReminderTime = "";
}
});
}
}
public async toggleHideRegisterPromptOnNewContact(): Promise<void> { public async toggleHideRegisterPromptOnNewContact(): Promise<void> {
const newSetting = !this.hideRegisterPromptOnNewContact; const newSetting = !this.hideRegisterPromptOnNewContact;
await this.$saveSettings({ await this.$saveSettings({

Loading…
Cancel
Save