tooot/src/utils/slices/instancesSlice.ts

423 lines
16 KiB
TypeScript
Raw Normal View History

2022-04-29 23:57:18 +02:00
import features from '@helpers/features'
2021-02-20 19:12:44 +01:00
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
2020-12-13 14:04:25 +01:00
import { RootState } from '@root/store'
2021-02-07 00:39:11 +01:00
import { ComposeStateDraft } from '@screens/Compose/utils/types'
import { InstanceLatest } from '@utils/migrations/instances/migration'
2021-02-20 19:12:44 +01:00
import addInstance from './instances/add'
2022-02-13 22:14:16 +01:00
import { checkEmojis } from './instances/checkEmojis'
2021-02-20 19:12:44 +01:00
import removeInstance from './instances/remove'
import { updateAccountPreferences } from './instances/updateAccountPreferences'
2021-11-15 22:34:43 +01:00
import { updateConfiguration } from './instances/updateConfiguration'
2021-05-30 23:39:07 +02:00
import { updateFilters } from './instances/updateFilters'
2021-02-27 16:33:54 +01:00
import { updateInstancePush } from './instances/updatePush'
import { updateInstancePushAlert } from './instances/updatePushAlert'
import { updateInstancePushDecode } from './instances/updatePushDecode'
2021-01-07 19:13:09 +01:00
2020-11-21 13:19:05 +01:00
export type InstancesState = {
instances: InstanceLatest[]
}
2021-01-07 19:13:09 +01:00
export const instancesInitialState: InstancesState = {
2021-02-20 19:12:44 +01:00
instances: []
2021-01-07 19:13:09 +01:00
}
const findInstanceActive = (instances: InstanceLatest[]) =>
2021-11-15 22:34:43 +01:00
instances.findIndex(instance => instance.active)
2021-02-20 19:12:44 +01:00
const instancesSlice = createSlice({
name: 'instances',
2021-01-07 19:13:09 +01:00
initialState: instancesInitialState,
2020-12-22 00:10:55 +01:00
reducers: {
2022-11-20 16:14:08 +01:00
updateInstanceActive: ({ instances }, action: PayloadAction<InstanceLatest>) => {
2021-02-20 19:12:44 +01:00
instances = instances.map(instance => {
instance.active =
2021-02-02 22:50:38 +01:00
instance.url === action.payload.url &&
instance.token === action.payload.token &&
instance.account.id === action.payload.account.id
2021-02-20 19:12:44 +01:00
return instance
})
2020-12-24 10:28:51 +01:00
},
2021-02-20 19:12:44 +01:00
updateInstanceAccount: (
{ instances },
2022-11-20 16:14:08 +01:00
action: PayloadAction<Pick<InstanceLatest['account'], 'acct' & 'avatarStatic'>>
2021-01-23 02:41:50 +01:00
) => {
2021-02-20 19:12:44 +01:00
const activeIndex = findInstanceActive(instances)
instances[activeIndex].account = {
...instances[activeIndex].account,
...action.payload
2021-01-23 02:41:50 +01:00
}
},
2021-03-17 15:30:28 +01:00
updateInstanceNotificationsFilter: (
{ instances },
action: PayloadAction<InstanceLatest['notifications_filter']>
2021-03-17 15:30:28 +01:00
) => {
const activeIndex = findInstanceActive(instances)
instances[activeIndex].notifications_filter = action.payload
},
2022-11-20 16:14:08 +01:00
updateInstanceDraft: ({ instances }, action: PayloadAction<ComposeStateDraft>) => {
2021-02-20 19:12:44 +01:00
const activeIndex = findInstanceActive(instances)
2022-01-30 22:51:03 +01:00
const draftIndex = instances[activeIndex].drafts.findIndex(
({ timestamp }) => timestamp === action.payload.timestamp
)
2021-02-20 19:12:44 +01:00
if (draftIndex === -1) {
instances[activeIndex].drafts.unshift(action.payload)
} else {
instances[activeIndex].drafts[draftIndex] = action.payload
2021-02-07 00:39:11 +01:00
}
},
2022-11-20 16:14:08 +01:00
removeInstanceDraft: ({ instances }, action: PayloadAction<ComposeStateDraft['timestamp']>) => {
2021-02-20 19:12:44 +01:00
const activeIndex = findInstanceActive(instances)
instances[activeIndex].drafts = instances[activeIndex].drafts?.filter(
draft => draft.timestamp !== action.payload
)
2021-03-04 01:03:53 +01:00
},
2021-03-23 23:16:01 +01:00
clearPushLoading: ({ instances }) => {
const activeIndex = findInstanceActive(instances)
instances[activeIndex].push.global.loading = false
instances[activeIndex].push.decode.loading = false
instances[activeIndex].push.alerts.favourite.loading = false
instances[activeIndex].push.alerts.follow.loading = false
instances[activeIndex].push.alerts.mention.loading = false
instances[activeIndex].push.alerts.poll.loading = false
instances[activeIndex].push.alerts.reblog.loading = false
},
2021-03-04 01:03:53 +01:00
disableAllPushes: ({ instances }) => {
instances = instances.map(instance => {
let newInstance = instance
newInstance.push.global.value = false
return newInstance
})
2022-01-16 23:26:05 +01:00
},
updateInstanceTimelineLookback: (
{ instances },
action: PayloadAction<InstanceLatest['timelinesLookback']>
2022-01-16 23:26:05 +01:00
) => {
const activeIndex = findInstanceActive(instances)
2022-02-06 18:09:11 +01:00
instances[activeIndex] &&
(instances[activeIndex].timelinesLookback = {
...instances[activeIndex].timelinesLookback,
...action.payload
})
2022-01-16 23:26:05 +01:00
},
updateInstanceMePage: (
{ instances },
action: PayloadAction<Partial<InstanceLatest['mePage']>>
2022-01-16 23:26:05 +01:00
) => {
const activeIndex = findInstanceActive(instances)
instances[activeIndex].mePage = {
...instances[activeIndex].mePage,
...action.payload
}
2022-02-13 22:14:16 +01:00
},
countInstanceEmoji: (
{ instances },
action: PayloadAction<InstanceLatest['frequentEmojis'][0]['emoji']>
2022-02-13 22:14:16 +01:00
) => {
const HALF_LIFE = 60 * 60 * 24 * 7 // 1 week
2022-11-20 16:14:08 +01:00
const calculateScore = (emoji: InstanceLatest['frequentEmojis'][0]): number => {
2022-02-13 22:14:16 +01:00
var seconds = (new Date().getTime() - emoji.lastUsed) / 1000
var score = emoji.count + 1
var order = Math.log(Math.max(score, 1)) / Math.LN10
var sign = score > 0 ? 1 : score === 0 ? 0 : -1
return (sign * order + seconds / HALF_LIFE) * 10
}
const activeIndex = findInstanceActive(instances)
const foundEmojiIndex = instances[activeIndex].frequentEmojis?.findIndex(
2022-11-20 16:14:08 +01:00
e => e.emoji.shortcode === action.payload.shortcode && e.emoji.url === action.payload.url
2022-02-13 22:14:16 +01:00
)
let newEmojisSort: InstanceLatest['frequentEmojis']
2022-02-13 22:14:16 +01:00
if (foundEmojiIndex > -1) {
newEmojisSort = instances[activeIndex].frequentEmojis
.map((e, i) =>
i === foundEmojiIndex
? {
2022-11-20 16:14:08 +01:00
...e,
score: calculateScore(e),
count: e.count + 1,
lastUsed: new Date().getTime()
}
2022-02-13 22:14:16 +01:00
: e
)
.sort((a, b) => b.score - a.score)
} else {
newEmojisSort = instances[activeIndex].frequentEmojis || []
const temp = {
emoji: action.payload,
score: 0,
count: 0,
lastUsed: new Date().getTime()
}
newEmojisSort.push({
...temp,
score: calculateScore(temp),
count: temp.count + 1
})
}
instances[activeIndex].frequentEmojis = newEmojisSort
.sort((a, b) => b.score - a.score)
.slice(0, 20)
2020-12-22 00:10:55 +01:00
}
},
extraReducers: builder => {
builder
2021-02-20 19:12:44 +01:00
.addCase(addInstance.fulfilled, (state, action) => {
2021-01-10 02:12:14 +01:00
switch (action.payload.type) {
case 'add':
2021-02-20 19:12:44 +01:00
state.instances.length &&
(state.instances = state.instances.map(instance => {
instance.active = false
return instance
}))
state.instances.push(action.payload.data)
2021-01-10 02:12:14 +01:00
break
case 'overwrite':
2021-02-20 19:12:44 +01:00
state.instances = state.instances.map(instance => {
2021-01-10 02:12:14 +01:00
if (
instance.url === action.payload.data.url &&
instance.account.id === action.payload.data.account.id
) {
return action.payload.data
} else {
2021-02-20 19:12:44 +01:00
instance.active = false
2021-01-10 02:12:14 +01:00
return instance
}
})
}
})
2021-02-20 19:12:44 +01:00
.addCase(addInstance.rejected, (state, action) => {
console.error(state.instances)
2021-01-07 19:13:09 +01:00
console.error(action.error)
})
2021-02-20 19:12:44 +01:00
.addCase(removeInstance.fulfilled, (state, action) => {
2021-03-01 00:28:14 +01:00
state.instances = state.instances.filter(instance => {
if (
instance.url === action.payload.url &&
instance.account.id === action.payload.account.id
) {
return false
} else {
return true
}
})
2022-11-20 16:14:08 +01:00
state.instances.length && (state.instances[state.instances.length - 1].active = true)
2021-01-07 19:13:09 +01:00
})
2021-02-20 19:12:44 +01:00
.addCase(removeInstance.rejected, (state, action) => {
console.error(state)
2021-01-07 19:13:09 +01:00
console.error(action.error)
2021-05-30 23:39:07 +02:00
})
// Update Instance Account Filters
.addCase(updateFilters.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].filters = action.payload
})
.addCase(updateFilters.rejected, (_, action) => {
console.error(action.error)
2021-01-07 19:13:09 +01:00
})
2021-02-27 16:33:54 +01:00
// Update Instance Account Preferences
2021-02-20 19:12:44 +01:00
.addCase(updateAccountPreferences.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].account.preferences = action.payload
2021-01-07 19:13:09 +01:00
})
2021-02-20 19:12:44 +01:00
.addCase(updateAccountPreferences.rejected, (_, action) => {
2021-01-07 19:13:09 +01:00
console.error(action.error)
})
2021-02-20 19:12:44 +01:00
2021-11-15 22:34:43 +01:00
// Update Instance Configuration
.addCase(updateConfiguration.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
2022-06-09 23:25:01 +02:00
state.instances[activeIndex].version = action.payload?.version || '0'
2022-11-20 16:14:08 +01:00
state.instances[activeIndex].configuration = action.payload.configuration
2021-11-15 22:34:43 +01:00
})
.addCase(updateConfiguration.rejected, (_, action) => {
console.error(action.error)
})
2021-02-27 16:33:54 +01:00
// Update Instance Push Global
.addCase(updateInstancePush.fulfilled, (state, action) => {
2021-02-20 19:12:44 +01:00
const activeIndex = findInstanceActive(state.instances)
2021-02-27 16:33:54 +01:00
state.instances[activeIndex].push.global.loading = false
state.instances[activeIndex].push.global.value = action.meta.arg
2021-12-06 21:25:09 +01:00
state.instances[activeIndex].push.keys = { auth: action.payload }
2021-02-27 16:33:54 +01:00
})
.addCase(updateInstancePush.rejected, state => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.global.loading = false
})
.addCase(updateInstancePush.pending, state => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.global.loading = true
})
// Update Instance Push Decode
.addCase(updateInstancePushDecode.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.decode.loading = false
2021-08-29 15:25:38 +02:00
state.instances[activeIndex].push.decode.value = action.payload.disable
2021-02-27 16:33:54 +01:00
})
.addCase(updateInstancePushDecode.rejected, state => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.decode.loading = false
})
.addCase(updateInstancePushDecode.pending, state => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.decode.loading = true
})
// Update Instance Push Individual Alert
.addCase(updateInstancePushAlert.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
2022-11-20 16:14:08 +01:00
state.instances[activeIndex].push.alerts[action.meta.arg.changed].loading = false
2021-02-27 16:33:54 +01:00
state.instances[activeIndex].push.alerts = action.payload
})
.addCase(updateInstancePushAlert.rejected, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
2022-11-20 16:14:08 +01:00
state.instances[activeIndex].push.alerts[action.meta.arg.changed].loading = false
2021-02-27 16:33:54 +01:00
})
.addCase(updateInstancePushAlert.pending, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
2022-11-20 16:14:08 +01:00
state.instances[activeIndex].push.alerts[action.meta.arg.changed].loading = true
2021-02-20 19:12:44 +01:00
})
2022-02-13 22:14:16 +01:00
// Check if frequently used emojis still exist
.addCase(checkEmojis.fulfilled, (state, action) => {
2022-05-17 23:26:29 +02:00
if (!action.payload || !action.payload.length) return
2022-02-13 22:14:16 +01:00
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].frequentEmojis = state.instances[
activeIndex
].frequentEmojis?.filter(emoji => {
2022-06-09 23:25:01 +02:00
return action.payload?.find(
2022-11-20 16:14:08 +01:00
e => e.shortcode === emoji.emoji.shortcode && e.url === emoji.emoji.url
2022-02-13 22:14:16 +01:00
)
})
})
.addCase(checkEmojis.rejected, (_, action) => {
console.error(action.error)
})
}
})
2021-02-20 19:12:44 +01:00
export const getInstanceActive = ({ instances: { instances } }: RootState) =>
findInstanceActive(instances)
2022-11-20 16:14:08 +01:00
export const getInstances = ({ instances: { instances } }: RootState) => instances
2021-02-20 19:12:44 +01:00
2021-11-15 22:34:43 +01:00
export const getInstance = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]
2021-02-20 19:12:44 +01:00
2021-11-15 22:34:43 +01:00
export const getInstanceUrl = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.url
2021-02-20 19:12:44 +01:00
2021-11-15 22:34:43 +01:00
export const getInstanceUri = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.uri
2021-02-20 19:12:44 +01:00
2021-11-15 22:34:43 +01:00
export const getInstanceUrls = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.urls
2021-02-20 19:12:44 +01:00
export const getInstanceVersion = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.version
2022-04-29 23:57:18 +02:00
export const checkInstanceFeature =
(feature: string) =>
2022-11-20 16:14:08 +01:00
({ instances: { instances } }: RootState): boolean => {
return (
features
.filter(f => f.feature === feature)
.filter(f => parseFloat(instances[findInstanceActive(instances)]?.version) >= f.version)
?.length > 0
)
}
2021-11-15 22:34:43 +01:00
/* Get Instance Configuration */
2022-11-20 16:14:08 +01:00
export const getInstanceConfigurationStatusMaxChars = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.configuration?.statuses.max_characters || 500
2021-02-20 19:12:44 +01:00
2021-11-15 22:34:43 +01:00
export const getInstanceConfigurationStatusMaxAttachments = ({
instances: { instances }
}: RootState) =>
2022-11-20 16:14:08 +01:00
instances[findInstanceActive(instances)]?.configuration?.statuses.max_media_attachments || 4
2021-11-15 22:34:43 +01:00
2022-11-20 16:14:08 +01:00
export const getInstanceConfigurationStatusCharsURL = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.configuration?.statuses.characters_reserved_per_url ||
23
2021-11-15 22:34:43 +01:00
2022-11-20 16:14:08 +01:00
export const getInstanceConfigurationMediaAttachments = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.configuration?.media_attachments || {
supported_mime_types: [
'image/jpeg',
'image/png',
'image/gif',
'video/webm',
'video/mp4',
'video/quicktime',
'video/ogg',
'audio/wave',
'audio/wav',
'audio/x-wav',
'audio/x-pn-wave',
'audio/ogg',
'audio/vorbis',
'audio/mpeg',
'audio/mp3',
'audio/webm',
'audio/flac',
'audio/aac',
'audio/m4a',
'audio/x-m4a',
'audio/mp4',
'audio/3gpp',
'video/x-ms-asf'
],
image_size_limit: 10485760,
image_matrix_limit: 16777216,
video_size_limit: 41943040,
video_frame_rate_limit: 60,
video_matrix_limit: 2304000
}
2022-11-20 16:14:08 +01:00
export const getInstanceConfigurationPoll = ({ instances: { instances } }: RootState) =>
2021-11-15 22:34:43 +01:00
instances[findInstanceActive(instances)]?.configuration?.polls || {
max_options: 4,
max_characters_per_option: 50,
min_expiration: 300,
max_expiration: 2629746
}
/* END */
export const getInstanceAccount = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.account
2021-02-20 19:12:44 +01:00
2022-11-20 16:14:08 +01:00
export const getInstanceNotificationsFilter = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.notifications_filter
2021-03-17 15:30:28 +01:00
2021-11-15 22:34:43 +01:00
export const getInstancePush = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.push
2021-02-27 16:33:54 +01:00
2022-11-20 16:14:08 +01:00
export const getInstanceTimelinesLookback = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.timelinesLookback
2022-01-16 23:26:05 +01:00
export const getInstanceMePage = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.mePage
2021-11-15 22:34:43 +01:00
export const getInstanceDrafts = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.drafts
2021-01-07 19:13:09 +01:00
2022-11-20 16:14:08 +01:00
export const getInstanceFrequentEmojis = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.frequentEmojis
2022-02-13 22:14:16 +01:00
2021-01-07 19:13:09 +01:00
export const {
2021-02-20 19:12:44 +01:00
updateInstanceActive,
updateInstanceAccount,
2021-03-17 15:30:28 +01:00
updateInstanceNotificationsFilter,
2021-02-20 19:12:44 +01:00
updateInstanceDraft,
2021-03-04 01:03:53 +01:00
removeInstanceDraft,
2021-03-23 23:16:01 +01:00
clearPushLoading,
2022-01-16 23:26:05 +01:00
disableAllPushes,
updateInstanceTimelineLookback,
2022-02-13 22:14:16 +01:00
updateInstanceMePage,
countInstanceEmoji
2021-01-07 19:13:09 +01:00
} = instancesSlice.actions
2020-12-22 00:10:55 +01:00
export default instancesSlice.reducer