diff --git a/.gitignore b/.gitignore index 178b02a..f2cbfd2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ dist-ssr *.sln *.sw? releases +src/client/inject.js diff --git a/CHANGELOG.MD b/CHANGELOG.MD index f542e7d..824e52b 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,5 +1,13 @@ # Change Log +## [Version 1.0.9] + +- added: browser notifications(work similar to push notifications) for comment, mention, follow with the ability to open the notification in app +- changed login to use app.yup.io +- removed external navigation to yup-live +- added more settings +- fixed some service worker issues + ## [Version 1.0.8] - migrated from windicss to tailwindcss @@ -13,7 +21,7 @@ ## [Version 1.0.6] -- refactored notifications +- refactored notifications - added support for aggregated notifications - added support for follow notification diff --git a/manifest.json b/manifest.json index 63c2d1a..1ff1746 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "yup live", "description": "Light alternative extension for yup protocol", - "version": "1.0.8", + "version": "1.0.9", "manifest_version": 3, "icons": { "16": "src/assets/icons/yup_ext_16.png", diff --git a/src/background/index.ts b/src/background/index.ts index 7ed7087..e52f91d 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,10 +1,11 @@ import { SEND_AUTH_NOTIF, ENABLE_RIGHT_CLICK, DISABLE_RIGHT_CLICK } from '@/constants/messeges'; import { initStorage } from '@/utils/storage' -import { getStore, setProfile, setNotifStorageNotifs, setSettings, setNotifStorageLastRewardNotif, getNotifStorageLastRewardNotif } from '@/utils/storage' +import { getStore, setProfile, setNotifStorageNotifs, setSettings, + setNotifStorageLastRewardNotif, getNotifStorageLastRewardNotif, getSetting, setSetting } from '@/utils/storage' import type { Notification } from '@/utils/types'; import { API_BASE } from '@/constants/config'; import { getNotifications } from '@/utils/notifications'; -import { setBadge } from '@/utils/chrome-misc' +import { setBadge, extrenalNavigate } from '@/utils/chrome-misc' import { closeTo } from '@/utils/time'; import { getActionUsage } from '@/utils/user'; import { executeVote, getVotePayload } from '@/utils/votes'; @@ -14,6 +15,27 @@ const yupExtensionId = 'nhmeoaahigiljjdkoagafdccikgojjoi' console.info('Service worker started') +let notificationUrl: string + +const buttons = { + buttons: [{ + title: 'Open in App', + }] +} + +const notificationActionListner = async (id: string) => { + try { + const url = new URL(notificationUrl ?? 'https://app.yup.io/notifications') + extrenalNavigate(url.href) + chrome.notifications.clear(id) + } catch { + // ignore + } +} + +if (!chrome.notifications.onButtonClicked.hasListener(notificationActionListner)){ + chrome.notifications.onButtonClicked.addListener(notificationActionListner) +} const onRightClickLike = async (store, info, tab) => { const vote = await executeVote(getVotePayload({ @@ -74,7 +96,7 @@ const alarmHandler = async () => { type: null, limit: '15', skip: '0', - userId: store.user.auth.userId + address: store.user.auth.address }) } requests.coinGecko = fetch('https://api.coingecko.com/api/v3/simple/price?ids=yup&vs_currencies=usd') @@ -114,8 +136,8 @@ const alarmHandler = async () => { } setSettings(updateSettings).catch(console.error) - if (store.settings?.chromeNotifWhenReward && notSeen.some(notif => notif.action === 'reward')) { - const rewardNotif = notSeen.find(notif => notif.action === 'reward') + if (store.settings?.chromeNotifWhenReward && notSeen.some(notif => notif.eventType === 'reward')) { + const rewardNotif = notSeen.find(notif => notif.eventType === 'reward') if (rewardNotif) { const storeReward = (await getNotifStorageLastRewardNotif()) @@ -128,13 +150,57 @@ const alarmHandler = async () => { type: 'basic', iconUrl: chrome.runtime.getURL('src/assets/icons/yup_ext_128.png'), title: 'Yup Live Extension', - message: `You have been alocated a future reward of ${rewardNotif.quantity} YUP`, + message: `You have been alocated a future reward of ${rewardNotif?.meta.quantity ?? "unknown"} YUP`, }) } } } + } else if (store.settings?.enableFollowNotif && notSeen.some(notif => notif.eventType === 'follow')) { + const followNotif = notSeen.filter(notif => notif.eventType === 'follow').sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())[0] + const lastFollowNotif = await getSetting('lastfollowNotif') as number + const isNew = !lastFollowNotif || ( !closeTo(new Date(lastFollowNotif), new Date(followNotif.createdAt), 2e4)) + if (followNotif && isNew) { + notificationUrl = followNotif?.senders?.[0]._id ? `${API_BASE}/account/${followNotif?.senders?.[0]._id}`: undefined + await chrome.notifications.create({ + type: 'basic', + iconUrl: chrome.runtime.getURL('src/assets/icons/yup_ext_128.png'), + title: 'Yup Live Extension', + message: `${followNotif.senders[0].handle} has followed you`, + ...(buttons) + }) + await setSetting('lastfollowNotif', new Date(followNotif.createdAt).getTime()) + } + } else if (store.settings?.enableCommentNotif && notSeen.some(notif => notif.eventType === 'comment')) { + const commentNotif = notSeen.filter(notif => notif.eventType === 'comment').sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())[0] + const lastCommentNotif = await getSetting('lastCommentNotif') as number + const isNew = !lastCommentNotif || ( !closeTo(new Date(lastCommentNotif), new Date(commentNotif.createdAt), 2e4)) + if (commentNotif && isNew) { + notificationUrl = commentNotif?.meta?.postid ? `${API_BASE}/post/${commentNotif?.meta?.postid}`: undefined + await chrome.notifications.create({ + type: 'basic', + iconUrl: chrome.runtime.getURL('src/assets/icons/yup_ext_128.png'), + title: 'Yup Live Extension', + message: `${commentNotif.senders[0].handle} has commented on your post`, + ...(buttons) + }) + await setSetting('lastCommentNotif', new Date(commentNotif.createdAt).getTime()) + } + } else if (store.settings?.enableMentionNotif && notSeen.some(notif => notif.eventType === 'mention')) { + const mentionNotif = notSeen.filter(notif => notif.eventType === 'mention').sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())[0] + const lastMentionNotif = await getSetting('lastMentionNotif') as number + const isNew = !lastMentionNotif || ( !closeTo(new Date(lastMentionNotif), new Date(mentionNotif.createdAt), 2e4)) + if (mentionNotif && isNew) { + notificationUrl = mentionNotif?.meta?.postid ? `${API_BASE}/post/${mentionNotif?.meta?.postid}`: undefined + await chrome.notifications.create({ + type: 'basic', + iconUrl: chrome.runtime.getURL('src/assets/icons/yup_ext_128.png'), + title: 'Yup Live Extension', + message: `${mentionNotif.senders[0].handle} has mentioned you`, + ...(buttons) + }) + await setSetting('lastMentionNotif', new Date(mentionNotif.createdAt).getTime()) + } } - if (store.settings?.chromeNotifWhenAbleToVote) { await getActionUsage(store?.user?.auth?.userId) } @@ -187,13 +253,16 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => { try { console.log('Message received', request) - if (request.type === SEND_AUTH_NOTIF) { + const lastLoginNotifTime = Number(await getSetting('lastLoginNotif')) + const moreThanOneDay = (new Date().getTime() - lastLoginNotifTime) > 864e5 + if (request.type === SEND_AUTH_NOTIF && moreThanOneDay) { chrome.notifications.create({ type: 'basic', iconUrl: chrome.runtime.getURL('src/assets/icons/yup_ext_128.png'), title: 'Yup Live Extension', message: 'You have been logged in.', }) + setSetting('lastLoginNotif', new Date().getTime()) sendResponse({ success: true }) } else if (request.type === ENABLE_RIGHT_CLICK) { await enableRightClickVote() diff --git a/src/client/inject.js b/src/client/inject.js deleted file mode 100644 index a886c38..0000000 --- a/src/client/inject.js +++ /dev/null @@ -1,42 +0,0 @@ -var SEND_VOTE = 'SEND_VOTE'; -var SET_AUTH = 'SET_AUTH'; -var WebCommunicator = /** @class */ (function () { - function WebCommunicator(injectAuthMethod) { - if (injectAuthMethod === void 0) { injectAuthMethod = false; } - var _this = this; - this._send = function (data) { - window.postMessage(data, "*"); - }; - this.submitVote = function (vote) { - return _this._send({ - type: SEND_VOTE, - payload: vote - }); - }; - this.setAuth = function (authData) { - return _this._send({ - type: SET_AUTH, - payload: authData - }); - }; - if (injectAuthMethod) { - ; - window.yupSetAuth = this.setAuth; - } - else { - ; - window.yupSetAuth = function () { return Promise.resolve(null); }; - } - ; - window.yupSubmitVote = this.submitVote; - } - return WebCommunicator; -}()); -var allowRegex = /^((http:|https:))?([/][/])?(www.)?[a-zA-Z\-_0-9]{0,}\.?[a-zA-Z\-_0-9]{0,}(yup.info.gf|yup-live.pages.dev|.yup.io|yup-team.vercel.app|localhost\/|localhost:)(.*)/gm; -var isAllowed = allowRegex.test(window.location.href); -if (isAllowed) { - new WebCommunicator(true); -} -else { - new WebCommunicator(); -} diff --git a/src/client/inject.ts b/src/client/inject.ts index 2b676e9..a0e0b38 100644 --- a/src/client/inject.ts +++ b/src/client/inject.ts @@ -35,6 +35,8 @@ class WebCommunicator { const allowRegex = /^((http:|https:))?([/][/])?(www.)?[a-zA-Z\-_0-9]{0,}\.?[a-zA-Z\-_0-9]{0,}(yup.info.gf|yup-live.pages.dev|.yup.io|yup-team.vercel.app|localhost\/|localhost:)(.*)/gm const isAllowed = allowRegex.test(window.location.href) +console.log('isAllowed', isAllowed) + if(isAllowed) { new WebCommunicator(true) } else { diff --git a/src/components/Notification.svelte b/src/components/Notification.svelte index eb0fa6b..4bd102f 100644 --- a/src/components/Notification.svelte +++ b/src/components/Notification.svelte @@ -9,6 +9,8 @@ let loader; + const appBase = "https://app.yup.io"; + export let notif: Notification; @@ -33,7 +35,7 @@

extrenalNavigate(`https://yup-live.pages.dev/post/${notif.meta.postid}`)} + on:click={() => extrenalNavigate(`${appBase}/post/${notif.meta.postid}`)} aria-hidden class="text-blue-200 interactive-svg">{finalUrl} @@ -105,7 +107,7 @@

extrenalNavigate(`https://yup-live.pages.dev/web3-profile/${sender?._id}`)} + on:click={() => extrenalNavigate(`${appBase}/account/${sender?._id}`)} > {sender?.handle || `${sender?._id?.slice(0, 6)}...`} followed you. diff --git a/src/constants/config.ts b/src/constants/config.ts index e609f96..9844b9a 100644 --- a/src/constants/config.ts +++ b/src/constants/config.ts @@ -1,4 +1,4 @@ export const API_BASE = 'https://api.yup.io' export const DEV_BASE = 'http://localhost:4566' -export const YUP_LIVE_BASE = 'https://yup-live.pages.dev' +export const YUP_LIVE_BASE = 'https://app.yup.io' export const APP_BASE = YUP_LIVE_BASE \ No newline at end of file diff --git a/src/pages/Login.svelte b/src/pages/Login.svelte index 59603fd..2f6323f 100644 --- a/src/pages/Login.svelte +++ b/src/pages/Login.svelte @@ -11,14 +11,10 @@

- - Login - - / - - Signup + + Login on web app
- + diff --git a/src/pages/Main.svelte b/src/pages/Main.svelte index 39b1b05..bba5a67 100644 --- a/src/pages/Main.svelte +++ b/src/pages/Main.svelte @@ -36,12 +36,12 @@
-
extrenalNavigate(`${APP_BASE}/score/${$mainStore.user.auth.address}`)} aria-hidden class="flex flex-col w-16 mt-1 px-2 py-3 mr-4 link"> + -
extrenalNavigate(`${APP_BASE}/profile/${$mainStore.user.auth.userId}`)} aria-hidden class="flex flex-col justify-center mb-1 w-16"> +
extrenalNavigate(`${APP_BASE}/account/${$mainStore.user.auth.userId}`)} aria-hidden class="flex flex-col justify-center mb-1 w-16"> {handle.length >= 12 ? handle.slice(0, 10) + "..." : handle} {/if}
-
extrenalNavigate(`${APP_BASE}/raw-influence/${$mainStore.user.auth.userId}`)} aria-hidden class="flex flex-col w-16 mt-1 ml-4 px-2 py-3 link"> + {:else} diff --git a/src/utils/storage.ts b/src/utils/storage.ts index 9de3bc4..0bbdf17 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -49,6 +49,13 @@ export const storageDefault = { refilNotifTimestamp: 0, enableRightClick: false, enableRightClickNotif: false, + lastLoginNotif: 0, + enableCommentNotif: false, + enableMentionNotif: false, + enableFollowNotif: false, + lastfollowNotif: 0, + lastCommentNotif: 0, + lastMentionNotif: 0, } } @@ -148,3 +155,14 @@ export const getSettings = async () => { return store ? store.store.settings as StorageType['settings'] : storageDefault.settings as StorageType['settings'] } +export const getSetting = async (setting: keyof StorageType['settings']) => { + const settings = await getSettings() + return settings[setting] +} + +export const setSetting = async (setting: K, value: StorageType['settings'][K]) => { + const settings = await getSettings() + settings[setting] = value + await setSettings(settings) +} + diff --git a/src/utils/types.ts b/src/utils/types.ts index 39168ce..f3ea9a3 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -33,4 +33,5 @@ export interface Vote { avatar: string }[] message?: string + seen: boolean }