nuxt-community / onesignal-module

OneSignal for Nuxt 2
MIT License
74 stars 8 forks source link

Nuxt 3 Support #49

Open harlan-zw opened 1 year ago

harlan-zw commented 1 year ago

Hey :wave: It looks like this module hasn't been updated for Nuxt 3. In an effort to improve the developer experience of modules, I've updated the module to clarify that it only supports Nuxt 2.

If Nuxt 3 support is added it will be moved to the https://github.com/nuxt-modules organisation.

Please let me know if you need any help :)

cc: @Geminii

simkuns commented 12 months ago

Simple OneSignal implementation in Nuxt 3 example.

Screenshot 2023-12-07 at 02 27 12
npm install --save-dev @onesignal/onesignal-vue3
// nuxt.config.ts
export default defineNuxtConfig({
  plugins: [
    'onesignal.client'
  ],
  runtimeConfig: {
    public: {
      onesignalAppId: '<ONESIGNAL_APP_ID>',
    },
  },
});
// plugins/onesignal.client
import { useOneSignal } from '@onesignal/onesignal-vue3';

export default defineNuxtPlugin((nuxtApp) => {
  const appId = nuxtApp.$config.public.onesignalAppId;

  if (!appId) {
    return;
  }

  const OneSignal = useOneSignal();

  OneSignal.init({
    appId,
    allowLocalhostAsSecureOrigin: process.env.APP_ENV !== 'production',
  });

  return {
    provide: {
      OneSignal,
    },
  };
});

This component uses @nuxtjs/i18n, @sidebase/nuxt-auth and vuetify with auto-imports enabled.

<!-- components/OneSignalSubscribeButton.vue -->
<template>
  <ClientOnly>
    <v-tooltip location="bottom">
      <template #activator="{ props }">
        <v-btn
          variant="text"
          icon
          class="me-2"
          v-bind="props"
          @click.prevent="onClickBellButton"
        >
          <v-icon :color="bellOption.color" :icon="bellOption.icon" />
        </v-btn>
      </template>
      <span>{{ bellOption.tooltipText }}</span>
    </v-tooltip>
  </ClientOnly>
</template>

<script lang="ts" setup>
const BELL_STATE = {
  DISABLED: 'disabled',
  SUBSCRIBE: 'subscribe',
  SUBSCRIBED: 'subscribed',
} as const;

type BellState = (typeof BELL_STATE)[keyof typeof BELL_STATE];

defineOptions({
  name: 'OneSignalSubscribeButton',
});

const { $OneSignal } = useNuxtApp();
const i18n = useI18n();
const auth = useAuth();

const bellState = ref<BellState>(BELL_STATE.DISABLED);

const bellOption = computed(() => {
  switch (bellState.value) {
  case BELL_STATE.SUBSCRIBE:
    return {
      color: 'info',
      icon: 'mdi-bell',
      tooltipText: i18n.t('onesignal.attributes.bell.subscribe'),
    };
  case BELL_STATE.SUBSCRIBED:
    return {
      color: 'success',
      icon: 'mdi-bell-check',
      tooltipText: i18n.t('onesignal.attributes.bell.subscribed'),
    };
  case BELL_STATE.DISABLED:
  default:
    return {
      color: 'info',
      icon: 'mdi-bell-off',
      tooltipText: i18n.t('onesignal.attributes.bell.disabled'),
    };
  }
});

watch(auth.status, (status) => {
  if (status === 'authenticated') {
    $OneSignal.login(String(auth.data.value?.id));
  }
});

onBeforeMount(() => {
  updateBellState();

  $OneSignal.Notifications.addEventListener('permissionChange', onPermissionChange);
  $OneSignal.User.PushSubscription.addEventListener('change', onSubscriptionChange);
});

onBeforeUnmount(() => {
  $OneSignal.Notifications.removeEventListener('permissionChange', onPermissionChange);
  $OneSignal.User.PushSubscription.removeEventListener('change', onSubscriptionChange);
});

async function onClickBellButton() {
  switch (bellState.value) {
  case BELL_STATE.SUBSCRIBED:
    await $OneSignal.User.PushSubscription.optOut();
    break;
  case BELL_STATE.SUBSCRIBE:
    await $OneSignal.User.PushSubscription.optIn();
    break;
  case BELL_STATE.DISABLED:
    // $OneSignal.Slidedown.promptPush({ force: true });
    await $OneSignal.Notifications.requestPermission();
    break;
  }
}

function onSubscriptionChange() {
  updateBellState();
}

function onPermissionChange(isAllowed: boolean) {
  if (isAllowed) {
    $OneSignal.User.PushSubscription.optIn();
  }
}

function getSubscriptionState() {
  return {
    isPushNotificationsEnabled: $OneSignal.Notifications.permission,
    isOptedIn: $OneSignal.User.PushSubscription.optedIn,
  };
}

function updateBellState() {
  const state = getSubscriptionState();

  if (!state.isPushNotificationsEnabled) {
    bellState.value = BELL_STATE.DISABLED;

    return;
  }

  if (!state.isOptedIn) {
    bellState.value = BELL_STATE.SUBSCRIBE;

    return;
  }

  bellState.value = BELL_STATE.SUBSCRIBED;
}
</script>

Showing bell only to authenticated users.

<!-- example.vue -->
<template>
  <div>
    <LazyOneSignalSubscribeButton
      v-if="'$OneSignal' in $nuxt && $config.public.onesignalAppId && auth.status.value === 'authenticated'"
    />
  </div>
</template>