<commit_before>// @flow

import {} from '../../lib/storage'

import {
	trackChannelSubscribe,
	trackChannelUnsubscribe,
	trackNotificationsDisable,
	trackNotificationsEnable,
} from '@frogpond/analytics'
import OneSignal, {
	type SubscriptionState,
	type TagsObject,
} from 'react-native-onesignal'
import pify from 'pify'

const getOneSignalTags: () => Promise<TagsObject> = pify(OneSignal.getTags, {
	errorFirst: false,
})
const getOneSignalPermissions: () => Promise<SubscriptionState> = pify(
	OneSignal.getPermissionSubscriptionState,
	{errorFirst: false},
)
const promptOneSignalPushPermission: () => Promise<boolean> = pify(
	OneSignal.promptForPushNotificationsWithUserResponse,
	{errorFirst: false},
)

import {type ReduxState} from '../index'

type Dispatch<A: Action> = (action: A | Promise<A> | ThunkAction<A>) => any
type GetState = () => ReduxState
type ThunkAction<A: Action> = (dispatch: Dispatch<A>, getState: GetState) => any

export type NotificationChannelName =
	| 'channel:campus/emergency'
	| 'channel:cage/late-night-specials'
	| 'channel:pause/monthly-special'
	| 'channel:multimedia/weekly-movie'
	| 'channel:post-office/packages'
	| 'channel:sga/announcements'

const CHANNEL_SUBSCRIBE = 'notifications/CHANNEL_SUBSCRIBE'
const CHANNEL_UNSUBSCRIBE = 'notifications/CHANNEL_UNSUBSCRIBE'
const CHANNELS_HYDRATE = 'notifications/CHANNELS_HYDRATE'
const DISABLE = 'notifications/DISABLE'
const ENABLE = 'notifications/ENABLE'

type ChannelSubscribeAction = {|
	type: 'notifications/CHANNEL_SUBSCRIBE',
	payload: NotificationChannelName,
|}
export function subscribe(
	channelName: NotificationChannelName,
): ChannelSubscribeAction {
	OneSignal.sendTag(channelName, 'active')
	trackChannelSubscribe(channelName)
	return {type: CHANNEL_SUBSCRIBE, payload: channelName}
}

type ChannelUnsubscribeAction = {|
	type: 'notifications/CHANNEL_UNSUBSCRIBE',
	payload: NotificationChannelName,
|}
export function unsubscribe(
	channelName: NotificationChannelName,
): ChannelUnsubscribeAction {
	OneSignal.deleteTag(channelName)
	trackChannelUnsubscribe(channelName)
	return {type: CHANNEL_UNSUBSCRIBE, payload: channelName}
}

type ToggleChannelSubscriptionAction =
	| ChannelSubscribeAction
	| ChannelUnsubscribeAction
export function toggleSubscription(
	channelName: NotificationChannelName,
): ThunkAction<ToggleChannelSubscriptionAction> {
	return (dispatch, getState) => {
		let {notifications: {channels = new Set()} = {}} = getState()

		if (channels.has(channelName)) {
			dispatch(unsubscribe(channelName))
		} else {
			dispatch(subscribe(channelName))
		}
	}
}

type HydrateChannelsAction = {|
	type: 'notifications/CHANNELS_HYDRATE',
	payload: {
		channels: Set<NotificationChannelName>,
		permissions: SubscriptionState,
	},
|}
export function hydrate(): ThunkAction<HydrateChannelsAction> {
	return async dispatch => {
		let [tags, permissions] = await Promise.all([
			getOneSignalTags(),
			getOneSignalPermissions(),
		])
		let channels = new Set(Object.keys(tags))
		dispatch({type: CHANNELS_HYDRATE, payload: {channels, permissions}})
	}
}

type DisableNotificationsAction = {|
	type: 'notifications/DISABLE',
|}
function disable(): DisableNotificationsAction {
	OneSignal.setSubscription(false)
	trackNotificationsDisable()
	return {type: DISABLE}
}

type EnableNotificationsAction = {|
	type: 'notifications/ENABLE',
|}
function enable(): ThunkAction<EnableNotificationsAction> {
	OneSignal.setSubscription(true)
	trackNotificationsEnable()
	return {type: ENABLE}
}

export function prompt() {
	return async dispatch => {
		const permissionResult = await promptOneSignalPushPermission()
		dispatch(permissionResult ? enable() : disable())<commit_msg>fix up flow types for enable/prompt actions<commit_after>// @flow

import {} from '../../lib/storage'

import {
	trackChannelSubscribe,
	trackChannelUnsubscribe,
	trackNotificationsDisable,
	trackNotificationsEnable,
} from '@frogpond/analytics'
import OneSignal, {
	type SubscriptionState,
	type TagsObject,
} from 'react-native-onesignal'
import pify from 'pify'

const getOneSignalTags: () => Promise<TagsObject> = pify(OneSignal.getTags, {
	errorFirst: false,
})
const getOneSignalPermissions: () => Promise<SubscriptionState> = pify(
	OneSignal.getPermissionSubscriptionState,
	{errorFirst: false},
)
const promptOneSignalPushPermission: () => Promise<boolean> = pify(
	OneSignal.promptForPushNotificationsWithUserResponse,
	{errorFirst: false},
)

import {type ReduxState} from '../index'

type Dispatch<A: Action> = (action: A | Promise<A> | ThunkAction<A>) => any
type GetState = () => ReduxState
type ThunkAction<A: Action> = (dispatch: Dispatch<A>, getState: GetState) => any

export type NotificationChannelName =
	| 'channel:campus/emergency'
	| 'channel:cage/late-night-specials'
	| 'channel:pause/monthly-special'
	| 'channel:multimedia/weekly-movie'
	| 'channel:post-office/packages'
	| 'channel:sga/announcements'

const CHANNEL_SUBSCRIBE = 'notifications/CHANNEL_SUBSCRIBE'
const CHANNEL_UNSUBSCRIBE = 'notifications/CHANNEL_UNSUBSCRIBE'
const CHANNELS_HYDRATE = 'notifications/CHANNELS_HYDRATE'
const DISABLE = 'notifications/DISABLE'
const ENABLE = 'notifications/ENABLE'

type ChannelSubscribeAction = {|
	type: 'notifications/CHANNEL_SUBSCRIBE',
	payload: NotificationChannelName,
|}
export function subscribe(
	channelName: NotificationChannelName,
): ChannelSubscribeAction {
	OneSignal.sendTag(channelName, 'active')
	trackChannelSubscribe(channelName)
	return {type: CHANNEL_SUBSCRIBE, payload: channelName}
}

type ChannelUnsubscribeAction = {|
	type: 'notifications/CHANNEL_UNSUBSCRIBE',
	payload: NotificationChannelName,
|}
export function unsubscribe(
	channelName: NotificationChannelName,
): ChannelUnsubscribeAction {
	OneSignal.deleteTag(channelName)
	trackChannelUnsubscribe(channelName)
	return {type: CHANNEL_UNSUBSCRIBE, payload: channelName}
}

type ToggleChannelSubscriptionAction =
	| ChannelSubscribeAction
	| ChannelUnsubscribeAction
export function toggleSubscription(
	channelName: NotificationChannelName,
): ThunkAction<ToggleChannelSubscriptionAction> {
	return (dispatch, getState) => {
		let {notifications: {channels = new Set()} = {}} = getState()

		if (channels.has(channelName)) {
			dispatch(unsubscribe(channelName))
		} else {
			dispatch(subscribe(channelName))
		}
	}
}

type HydrateChannelsAction = {|
	type: 'notifications/CHANNELS_HYDRATE',
	payload: {
		channels: Set<NotificationChannelName>,
		permissions: SubscriptionState,
	},
|}
export function hydrate(): ThunkAction<HydrateChannelsAction> {
	return async dispatch => {
		let [tags, permissions] = await Promise.all([
			getOneSignalTags(),
			getOneSignalPermissions(),
		])
		let channels = new Set(Object.keys(tags))
		dispatch({type: CHANNELS_HYDRATE, payload: {channels, permissions}})
	}
}

type DisableNotificationsAction = {|
	type: 'notifications/DISABLE',
|}
function disable(): DisableNotificationsAction {
	OneSignal.setSubscription(false)
	trackNotificationsDisable()
	return {type: DISABLE}
}

type EnableNotificationsAction = {|
	type: 'notifications/ENABLE',
|}
function enable(): EnableNotificationsAction {
	OneSignal.setSubscription(true)
	trackNotificationsEnable()
	return {type: ENABLE}
}

export function prompt(): ThunkAction<
	EnableNotificationsAction | DisableNotificationsAction,
> {
	return async dispatch => {
		const permissionResult = await promptOneSignalPushPermission()
		dispatch(permissionResult ? enable() : disable())
{'fraction_non_alphanumeric': 0.11307609860664523, 'fraction_numerical': 0.0, 'mean_word_length': 6.907838983050848, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1540142', 'n_tokens_mistral': 2364, 'n_tokens_neox': 2304, 'n_words': 456}