Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeljscript committed Sep 10, 2024
1 parent 16dec34 commit f3648c5
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 3 deletions.
3 changes: 3 additions & 0 deletions packages/notifications/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,8 @@
"preset": "angular"
}
}
},
"dependencies": {
"rxjs": "^7.8.1"
}
}
76 changes: 75 additions & 1 deletion packages/notifications/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,75 @@
export const NotificationManager = {}
import {BehaviorSubject} from 'rxjs'

export enum NotificationTrigger {
'TransactionReceived' = 'TransactionReceived',
'RewardsUpdated' = 'RewardsUpdated',
'PrimaryTokenPriceChanged' = 'PrimaryTokenPriceChanged',
}

export interface NotificationTransactionReceivedEvent
extends NotificationEventBase {
trigger: NotificationTrigger.TransactionReceived
metadata: {
previousTxsCounter: number
nextTxsCounter: number
txId: string
isSentByUser: boolean // check local pending
}
}

export type Group = 'transaction-history' | 'portfolio'

type NotificationTriggerPerGroup = {
'transaction-history':
| NotificationTrigger.TransactionReceived
| NotificationTrigger.RewardsUpdated
'portfolio': NotificationTrigger.PrimaryTokenPriceChanged
}

export type NotificationEvent = NotificationTransactionReceivedEvent

type NotificationEventId = string

interface NotificationEventBase {
id: string // uuid
date: number
isRead: boolean
}

export type NotificationConfig = {
[NotificationTrigger.PrimaryTokenPriceChanged]: {
notify: boolean
threshold: number
interval: '24h' | '1h'
}
[NotificationTrigger.TransactionReceived]: {
notify: boolean
}
[NotificationTrigger.RewardsUpdated]: {
notify: boolean
}
}

export type NotificationManager = {
hydrate: () => void // build up subscriptions
unreadCounterByGroup$: BehaviorSubject<Readonly<Map<Group, number>>>

// NOTE: events represent a notification event that was trigger by a config rule
events: {
markAllAsRead: () => void
markAsRead(id: NotificationEventId): void
read: () => Promise<ReadonlyArray<NotificationEvent>>
save: (event: Readonly<NotificationEvent>) => void
clear: () => void
}
// NOTE: config sets the ground to what, when, and if should notify user
config: {
read: () => Promise<Readonly<NotificationConfig>> // return initial if empty
save: (config: Readonly<NotificationConfig>) => Promise<void>
reset: () => Promise<void>
}
destroy: () => void // tear down subscriptions
clear: () => void
}

// TODO: Add trackers - these are only pointers to last notification event
16 changes: 14 additions & 2 deletions packages/notifications/src/notification-manager.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import {NotificationManager} from './index'
import {notificationManagerMaker} from './notification-manager'

describe('NotificationManager', () => {
it('should be defined', () => {
expect(NotificationManager).toBeDefined()
expect(notificationManagerMaker()).toBeDefined()
})

it('should return default config if not set', async () => {
const manager = notificationManagerMaker()
const config = await manager.config.read()
expect(config).toEqual({
PrimaryTokenPriceChanged: {
interval: '24h',
notify: true,
threshold: 10,
},
})
})
})
109 changes: 109 additions & 0 deletions packages/notifications/src/notification-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Group,
NotificationConfig,
NotificationEvent,
NotificationManager,
NotificationTrigger,
} from './index'
import {BehaviorSubject} from 'rxjs'
import {App} from '@yoroi/types'

type NotificationManagerMakerProps = {
eventsStorage: App.Storage<true, string>
configStorage: App.Storage<true, string>
}

type EventsStorageData = ReadonlyArray<NotificationEvent>
type ConfigStorageData = NotificationConfig

export const notificationManagerMaker = ({
eventsStorage,
configStorage,
}: NotificationManagerMakerProps): NotificationManager => {
const hydrate = () => {}

const events = eventsManagerMaker({storage: eventsStorage})
const config = configManagerMaker({storage: configStorage})

const destroy = () => {}

const clear = async () => {
await config.reset()
await events.clear()
}

const unreadCounterByGroup$ = new BehaviorSubject<Map<Group, number>>(
new Map<Group, number>(),
)

return {hydrate, clear, destroy, events, config, unreadCounterByGroup$}
}

const eventsManagerMaker = ({
storage,
}: {
storage: App.Storage<true, string>
}): NotificationManager['events'] => {
const events = {
markAllAsRead: async () => {
const allEvents = await events.read()
const modifiedEvents = allEvents.map((event) => ({
...event,
isRead: true,
}))
await storage.setItem<EventsStorageData>('events', modifiedEvents)
},
markAsRead: async (id: string) => {
const allEvents = await events.read()
const modifiedEvents = allEvents.map((event) =>
event.id === id ? {...event, isRead: true} : event,
)
await storage.setItem<EventsStorageData>('events', modifiedEvents)
},
read: async (): Promise<EventsStorageData> => {
return (await storage.getItem<EventsStorageData>('events')) ?? []
},
save: async (event: Readonly<NotificationEvent>) => {
const allEvents = await events.read()
await storage.setItem('events', [...allEvents, event])
},
clear: (): Promise<void> => {
return storage.removeItem('events')
},
}
return events
}

const configManagerMaker = ({
storage,
}: {
storage: App.Storage<true, string>
}): NotificationManager['config'] => {
return {
read: async (): Promise<NotificationConfig> => {
return (
(await storage.getItem<ConfigStorageData>('config')) ?? defaultConfig
)
},
save: async (config: NotificationConfig): Promise<void> => {
await storage.setItem('config', config)
},
reset: async (): Promise<void> => {
return storage.removeItem('config')
},
}
}

const defaultConfig: NotificationConfig = {
[NotificationTrigger.PrimaryTokenPriceChanged]: {
notify: true,
threshold: 10,
interval: '24h',
},
[NotificationTrigger.TransactionReceived]: {
notify: true,
},
[NotificationTrigger.RewardsUpdated]: {
notify: true,
},
}

0 comments on commit f3648c5

Please sign in to comment.