import { createAction as e, createSelector as t, createSlice as i } from "@reduxjs/toolkit"
import { isFeatureSupported as r, FEATURES as n } from "@holepunchto/keet-core/features"
import {
IDENTITY_MEMBER_STATUS as c,
IDENTITY_STATUS as a,
IDENTITY_USERNAME_STATUS as s,
IDENTITY_USERNAME_SAVE_STATUS as o,
QUERY_IDENTITY_SOURCE as d,
MAX_REMAINING_EDITS as y,
AVATAR_BASE_EMPTY_URL as I,
} from "./identity.constants"
import { normalizeIdentity as u, phraseToWords as m } from "./identity.model"
import {
IDENTITY_MEMBER_INITIAL_STATE as p,
IDENTITY_MEMBER_STATE_KEY as v,
} from "./member/identity-member.constant"
import { identityMemberSlice as g } from "./member"
import { getPreferencesRecoveryPhraseMigrationDeclined as S } from "../preferences"
export const IDENTITY_STATE_KEY = "identity"
export const BACKUP_CREATE_INITIAL_STATE = {
agreement: !1,
loading: !1,
errorMsg: "",
success: !1,
secretWords: [],
checkWords: [],
quickSetup: !1,
}
export const MIGRATE_RECOVERY_PHRASE_INITIAL_STATE = {
error: !1,
loading: !1,
manyRetries: !1,
success: !1,
}
export const SYNC_DEVICE_INITIAL_STATE = {
agreement: !1,
errorMsg: "",
waitingIdentity: !1,
success: !1,
seedId: "",
}
const l = { isSearching: !1, list: [] }
export const MY_IDENTITY_INITIAL_STATE = {
status: a.UNKNOWN,
avatar: null,
avatarUrl: "",
avatarUrlMedium: "",
displayName: "",
color: "",
username: "",
confirmed: !1,
local: {},
memberId: "",
profileId: "",
searchResults: { [d.GLOBAL]: l, [d.START_NEW_CHAT]: l },
selectedProfile: { contactInfo: null },
usernameStatus: s.UNKNOWN,
createUsernameStatus: o.UNKNOWN,
deviceLoading: !1,
deviceLoadError: "",
invitationLink: "",
invitedDevices: [],
devices: [],
secretPhrase: "",
hasDiscoveryKey: void 0,
hasSecretPhraseStored: !1,
agreement: !1,
contactInvitation: "",
actionType: void 0,
usernameError: void 0,
usernameEditCounts: null,
loggedOut: !1,
settings: { disableReadReceipts: !1 },
privateProfileVersion: null,
}
export const DEVICE_REMOVAL_INITIAL_STATE = { isLoading: !1, isError: !1, isSuccess: !1 }
export const INITIAL_STATE = {
accountRecover: { agreement: !1, loading: !1, errorMsg: "", success: !1 },
migrateRecoveryPhrase: MIGRATE_RECOVERY_PHRASE_INITIAL_STATE,
backupCreate: BACKUP_CREATE_INITIAL_STATE,
syncDevice: SYNC_DEVICE_INITIAL_STATE,
myIdentity: MY_IDENTITY_INITIAL_STATE,
[v]: p,
peerIdentity: { byId: {} },
privateProfileStats: {},
termsOfService: !1,
removeDeviceStatus: DEVICE_REMOVAL_INITIAL_STATE,
}
export const identitySlice = i({
name: "identity",
initialState: INITIAL_STATE,
reducers: {
setAccountRecoveryAgreement: (e, { payload: t }) => {
e.accountRecover.agreement = t
},
setAccountRecoverySuccess: (e) => {
;((e.accountRecover.success = !0), (e.accountRecover.loading = !1))
},
setAccountRecoveryError: (e, { payload: t }) => {
;((e.accountRecover.errorMsg = t.message), (e.accountRecover.loading = !1))
},
submitAccountRecovery: (e, t) => {
;((e.accountRecover.loading = !0), (e.accountRecover.errorMsg = ""))
},
resetAccountRecovery: (e) => {
e.accountRecover = { ...e.accountRecover, loading: !1, errorMsg: "", success: !1 }
},
setBackupCreateAgreement: (e, { payload: t }) => {
e.backupCreate.agreement = t
},
setBackupCreateErrorMsg: (e) => {
e.backupCreate.errorMsg = ""
},
setBackupCreateSecretPhrase: (e, { payload: t }) => {
e.backupCreate.secretWords = m(t)
},
setBackupCreateCheckWords: (e, { payload: t }) => {
e.backupCreate.checkWords = t
},
submitBackupCreate: (e) => {
;((e.backupCreate.errorMsg = ""), (e.backupCreate.loading = !0))
},
createAndSubmitBackup: (e, { payload: t }) => {
;((e.backupCreate.errorMsg = ""),
(e.backupCreate.quickSetup = !t),
(e.backupCreate.agreement = !0),
(e.backupCreate.loading = !0),
(e.backupCreate.secretWords = []))
},
submitBackupSuccess: (e) => {
;((e.backupCreate.loading = !1), (e.backupCreate.success = !0))
},
resetBackupCreate: (e) => {
e.backupCreate = { ...BACKUP_CREATE_INITIAL_STATE, agreement: e.backupCreate.agreement }
},
setMigrateRecoveryPhrase: (e, t) => {
e.migrateRecoveryPhrase = { ...e.migrateRecoveryPhrase, ...t.payload }
},
updateIdentityDeviceRequest: (e, t) => {
;((e.myIdentity.deviceLoading = !0), (e.myIdentity.deviceLoadError = ""))
},
updateIdentityDeviceSuccess: (e, { payload: t }) => {
const { deviceId: i, name: r } = t
;((e.myIdentity.deviceLoading = !1),
(e.myIdentity.devices = e.myIdentity.devices.map((e) =>
e.deviceId === i ? { ...e, name: r } : e,
)))
},
updateIdentityDeviceFailure: (e, { payload: t }) => {
;((e.myIdentity.deviceLoading = !1), (e.myIdentity.deviceLoadError = t.message))
},
setSyncDeviceAgreement: (e, { payload: t }) => {
e.syncDevice.agreement = t
},
setSyncDeviceErrorMsg: (e, { payload: t }) => {
e.syncDevice.errorMsg = t
},
setSyncDeviceSeedId: (e, { payload: t }) => {
;((e.syncDevice.seedId = t),
(e.syncDevice.agreement = !0),
(e.syncDevice.waitingIdentity = !0))
},
initSyncDevice: (e) => {
e.syncDevice.seedId ||
(e.syncDevice = {
...e.syncDevice,
errorMsg: "",
success: !1,
waitingIdentity: !1,
seedId: "",
})
},
cancelSyncDeviceSuccess: (e) => {
e.syncDevice = {
agreement: e.syncDevice.agreement,
errorMsg: "",
waitingIdentity: !1,
success: !1,
seedId: "",
}
},
setIdentityAsked: (e) => {
e.myIdentity.status === a.UNKNOWN && (e.myIdentity.status = a.ASKED)
},
setIdentity: (e, t) => {
const { payload: i } = t,
r = u(i),
n = r.memberId !== e.myIdentity.memberId,
c = r.devices.filter(({ confirmed: e, deviceId: t }) => e && t)
;((e.myIdentity = { ...e.myIdentity, ...r, devices: c }),
n &&
e.syncDevice.waitingIdentity &&
(e.syncDevice = {
...SYNC_DEVICE_INITIAL_STATE,
agreement: e.syncDevice.agreement,
success: !0,
}),
0 !== e.myIdentity.invitedDevices.length &&
c.forEach((t) => {
if (!("deviceId" in t)) return
const { deviceId: i } = t,
r = e.myIdentity.invitedDevices.findIndex((e) => e.deviceId === i)
;-1 !== r && e.myIdentity.invitedDevices.splice(r, 1)
}))
},
setIdentityAgreement: (e, { payload: t }) => {
e.myIdentity.agreement = t
},
setIdentityInvitationLink: (e, { payload: t }) => {
e.myIdentity.invitationLink = t
},
setIdentitySecretPhrase: (e, { payload: t }) => {
e.myIdentity.secretPhrase = t || MY_IDENTITY_INITIAL_STATE.secretPhrase
},
setIdentityHasSecretPhraseStored: (e, { payload: t }) => {
e.myIdentity.hasSecretPhraseStored = t
},
setIdentityContactInvitation: (e, { payload: t }) => {
e.myIdentity.contactInvitation = t
},
setIdentityUsernameActionType: (e, { payload: t }) => {
e.myIdentity.actionType = t
},
setPrivateProfileStats: (e, { payload: t }) => {
e.privateProfileStats = t
},
cancelIdentityInvitationLink: (e) => {
e.myIdentity.invitationLink = ""
},
addIdentityInvitedDevice: (e, { payload: t }) => {
t?.deviceId &&
((e.myIdentity.invitedDevices = e.myIdentity.invitedDevices.filter(
(e) => e.deviceId !== t.deviceId,
)),
e.myIdentity.invitedDevices.push(t),
(e.myIdentity.invitationLink = ""))
},
removeIdentityInvitedDevice: (e, { payload: t }) => {
e.myIdentity.invitedDevices = e.myIdentity.invitedDevices.filter((e) => e.deviceId !== t)
},
setTermsOfService: (e, { payload: t }) => {
e.termsOfService = t
},
queryIdentityRecords: (e, { payload: t }) => {
const i = t.opts?.source || d.GLOBAL
;((e.myIdentity.searchResults[i].isSearching = !0), (e.myIdentity.searchResults[i].list = []))
},
updateIdentitySearchList: (e, { payload: t }) => {
const { list: i, source: r = d.GLOBAL } = t
;((e.myIdentity.searchResults[r].isSearching = !1), (e.myIdentity.searchResults[r].list = i))
},
updateIdentitySelectedProfile: (e, { payload: t }) => {
e.myIdentity.selectedProfile = { contactInfo: t }
},
updateIdentityVerifyStatus: (e, { payload: t }) => {
e.myIdentity.usernameStatus = t
},
resetIdentityVerifyStatus: (e) => {
e.myIdentity.usernameStatus = s.UNKNOWN
},
updateUsernameReservationInfo: (e, t) => {
const { error: i, username: r, status: n, count: c } = t.payload || {}
;(n === o.RESERVED && (e.myIdentity.actionType = void 0),
(e.myIdentity.createUsernameStatus = n ?? e.myIdentity.createUsernameStatus),
(e.myIdentity.username = r ?? e.myIdentity.username),
(e.myIdentity.usernameError = i ?? e.myIdentity.usernameError),
(e.myIdentity.usernameEditCounts = c ?? e.myIdentity.usernameEditCounts))
},
resetUsernameReservationInfo: (e) => {
;((e.myIdentity.usernameError = void 0), (e.myIdentity.createUsernameStatus = o.NOT_STARTED))
},
updatePeerIdentity: (e, { payload: t }) => {
const { memberId: i, identityRecord: r } = t
e.peerIdentity.byId[i] = { status: c.LOADED, ...r }
},
updateRemoveDeviceStatus: (e, { payload: t }) => {
e.removeDeviceStatus = { ...e.removeDeviceStatus, ...t }
},
setPrivateProfileVersion: (e, { payload: t }) => {
e.myIdentity.privateProfileVersion = t
},
},
extraReducers: (e) => {
e.addDefaultCase((e, t) => {
e[v] = g.reducer(e[v], t)
})
},
})
export const getIdentityState = (e) => e.identity
export const getAccountRecoveryAgreement = (e) => getIdentityState(e).accountRecover.agreement
export const getAccountRecoveryLoading = (e) => getIdentityState(e).accountRecover.loading
export const getAccountRecoveryErrorMsg = (e) => getIdentityState(e).accountRecover.errorMsg
export const getAccountRecoverySuccess = (e) => getIdentityState(e).accountRecover.success
export const getBackupCreateAgreement = (e) => getIdentityState(e).backupCreate.agreement
export const getBackupCreateLoading = (e) => getIdentityState(e).backupCreate.loading
export const getBackupCreateQuickSetup = (e) => getIdentityState(e).backupCreate.quickSetup
export const getBackupCreateErrorMsg = (e) => getIdentityState(e).backupCreate.errorMsg
export const getBackupCreateSuccess = (e) => getIdentityState(e).backupCreate.success
export const getBackupCreateSecretWords = (e) => getIdentityState(e).backupCreate.secretWords
export const getBackupCreateCheckWords = (e) => getIdentityState(e).backupCreate.checkWords
export const getSyncDeviceAgreement = (e) => getIdentityState(e).syncDevice.agreement
export const getSyncDeviceErrorMsg = (e) => getIdentityState(e).syncDevice.errorMsg
export const getSyncDeviceWaitingIdentity = (e) => getIdentityState(e).syncDevice.waitingIdentity
export const getSyncDeviceSuccess = (e) => getIdentityState(e).syncDevice.success
export const getSyncDeviceSeedId = (e) => getIdentityState(e).syncDevice.seedId
export const getMyIdentity = (e) => getIdentityState(e).myIdentity
export const getIdentityDevices = (e) => getIdentityState(e).myIdentity.devices
export const getIdentityDeviceCurrent = t([getIdentityDevices], (e) => e.find((e) => !!e.current))
export const getIdentityStatus = (e) => getIdentityState(e).myIdentity.status
export const getIdentityMigrateRecoveryPhrase = (e) => getIdentityState(e).migrateRecoveryPhrase
export const getIdentityShouldMigrateRecoveryPhrase = (e) =>
!1 === getIdentityState(e).myIdentity.hasDiscoveryKey
export const getMigrateRecoveryPhraseBannerVisible = (e) =>
getIdentityShouldMigrateRecoveryPhrase(e) && !S(e)
export const getIdentityProfile = t(
(e) => getIdentityState(e).myIdentity,
({
avatar: e,
avatarUrl: t,
avatarUrlMedium: i,
displayName: r,
username: n,
memberId: c,
color: a,
}) => ({
avatar: e,
avatarUrl: t,
avatarUrlMedium: i,
displayName: r,
username: n,
memberId: c,
color: a,
}),
)
export const getMyMemberId = (e) => getIdentityState(e).myIdentity.memberId
export const getMyContactInvitation = (e) => getIdentityState(e).myIdentity.contactInvitation
export const getIsIdentityComplete = (e) => getIdentityStatus(e) === a.COMPLETE
export const getIsIdentityNameSet = (e) => {
const { displayName: t } = getIdentityState(e).myIdentity
return !!t && !/^\s/.test(t)
}
export const getHasIdentityUsername = (e) => !!getIdentityState(e).myIdentity.username
export const getIsIdentityConfirmed = (e) => getIdentityState(e).myIdentity.confirmed
export const getIsIdentityLoggedOut = (e) => getIdentityState(e).myIdentity.loggedOut
export const getIdentityInvitationLink = (e) => getIdentityState(e).myIdentity.invitationLink
export const getIdentityInvitedDevices = (e) => getIdentityState(e).myIdentity.invitedDevices
export const getIdentitySecretPhrase = (e) => getIdentityState(e).myIdentity.secretPhrase
export const getIdentityAgreement = (e) => getIdentityState(e).myIdentity.agreement
export const getIdentityHasSecretPhraseStored = (e) =>
getIdentityState(e).myIdentity.hasSecretPhraseStored
export const getPrivateProfileStats = (e) => getIdentityState(e).privateProfileStats
export const getIdentityProfileName = (e) => getIdentityProfile(e).displayName
export const getIdentityProfileAvatarUrl = (e) => {
const { avatarUrl: t } = getIdentityProfile(e)
return t === I ? "" : t
}
export const getIdentityProfileAvatarUrlMedium = (e) => getIdentityProfile(e).avatarUrlMedium
export const getIdentityProfileColor = (e) => getIdentityProfile(e).color
export const getTermsOfService = (e) => getIdentityState(e).termsOfService
export const getIdentityDeviceLoading = (e) => getIdentityState(e).myIdentity.deviceLoading
export const getIdentityDeviceLoadError = (e) => getIdentityState(e).myIdentity.deviceLoadError
export const getIdentitySearchResult =
(e = d.GLOBAL) =>
(t) =>
getIdentityState(t).myIdentity.searchResults[e] || l
export const getIdentitySelectedProfile = (e) => getIdentityState(e).myIdentity.selectedProfile
export const getIdentitySearchResultList = (e) => (t) => getIdentitySearchResult(e)(t).list
export const getIdentitySearchResultIsSearching = (e) => (t) =>
getIdentitySearchResult(e)(t).isSearching
export const getIdentityUsernameStatus = (e) => getIdentityState(e).myIdentity.usernameStatus
export const getCreateUsernameStatus = (e) => getIdentityState(e).myIdentity.createUsernameStatus
export const getPeerIdentityById = (e) => getIdentityState(e).peerIdentity.byId
export const getPeerIdentityByMemberId = (e) => (t) => getPeerIdentityById(t)[e]
export const getPeerIdentityUsernameByMemberId = (e) => (t) => getPeerIdentityById(t)[e]?.username
export const getIdentityUsernameActionType = (e) => getIdentityState(e).myIdentity.actionType
export const getRemainingEdits = (e) => {
const t = getIdentityState(e).myIdentity.usernameEditCounts
return t ? y - t : null
}
export const getCanEditUsername = t(
[(e) => getIdentityState(e).myIdentity, (e) => getRemainingEdits(e)],
({ createUsernameStatus: e, username: t }, i) =>
t && e !== o.RESERVING && e !== o.EDITING_LIMIT_EXCEEDED && null != i && i > 0,
)
export const getRemoveDeviceStatus = (e) => getIdentityState(e).removeDeviceStatus
export const getUsernameError = (e) => getIdentityState(e).myIdentity.usernameError
export const getIsReadReceiptsDisabled = (e) =>
getIdentityState(e).myIdentity.settings.disableReadReceipts
export const getPrivateProfileVersion = (e) => getIdentityState(e).myIdentity.privateProfileVersion
export const getIsReadReceiptsSupported = (e) => {
const t = getPrivateProfileVersion(e)
return r(t, n.PRIVATE_PROFILE_SETTINGS)
}
export const getIsFavoriteRoomSupported = (e) => {
const t = getPrivateProfileVersion(e)
return r(t, n.FAVORITE_ROOMS)
}
export const getIsRoomMarkUnreadSupported = (e) => {
const t = getPrivateProfileVersion(e)
return r(t, n.ROOM_MARK_UNREAD)
}
export const {
setAccountRecoveryAgreement: setAccountRecoveryAgreement,
setAccountRecoverySuccess: setAccountRecoverySuccess,
setAccountRecoveryError: setAccountRecoveryError,
submitAccountRecovery: submitAccountRecovery,
resetAccountRecovery: resetAccountRecovery,
setBackupCreateAgreement: setBackupCreateAgreement,
setBackupCreateErrorMsg: setBackupCreateErrorMsg,
setBackupCreateSecretPhrase: setBackupCreateSecretPhrase,
setBackupCreateCheckWords: setBackupCreateCheckWords,
submitBackupCreate: submitBackupCreate,
createAndSubmitBackup: createAndSubmitBackup,
submitBackupSuccess: submitBackupSuccess,
resetBackupCreate: resetBackupCreate,
setMigrateRecoveryPhrase: setMigrateRecoveryPhrase,
setSyncDeviceAgreement: setSyncDeviceAgreement,
setSyncDeviceErrorMsg: setSyncDeviceErrorMsg,
setSyncDeviceSeedId: setSyncDeviceSeedId,
addIdentityInvitedDevice: addIdentityInvitedDevice,
removeIdentityInvitedDevice: removeIdentityInvitedDevice,
initSyncDevice: initSyncDevice,
cancelSyncDeviceSuccess: cancelSyncDeviceSuccess,
setIdentity: setIdentity,
setIdentityContactInvitation: setIdentityContactInvitation,
setIdentityAsked: setIdentityAsked,
setIdentityInvitationLink: setIdentityInvitationLink,
setIdentitySecretPhrase: setIdentitySecretPhrase,
setIdentityAgreement: setIdentityAgreement,
setIdentityHasSecretPhraseStored: setIdentityHasSecretPhraseStored,
setIdentityUsernameActionType: setIdentityUsernameActionType,
cancelIdentityInvitationLink: cancelIdentityInvitationLink,
setTermsOfService: setTermsOfService,
updateIdentityDeviceRequest: updateIdentityDeviceRequest,
updateIdentityDeviceSuccess: updateIdentityDeviceSuccess,
updateIdentityDeviceFailure: updateIdentityDeviceFailure,
queryIdentityRecords: queryIdentityRecords,
updateIdentitySearchList: updateIdentitySearchList,
updateIdentitySelectedProfile: updateIdentitySelectedProfile,
updateIdentityVerifyStatus: updateIdentityVerifyStatus,
updateUsernameReservationInfo: updateUsernameReservationInfo,
resetIdentityVerifyStatus: resetIdentityVerifyStatus,
resetUsernameReservationInfo: resetUsernameReservationInfo,
updatePeerIdentity: updatePeerIdentity,
updateRemoveDeviceStatus: updateRemoveDeviceStatus,
setPrivateProfileStats: setPrivateProfileStats,
setPrivateProfileVersion: setPrivateProfileVersion,
} = identitySlice.actions
export const askBackupCreateSecretWords = e("identity/ask-backup-create-secret-words")
export const resetBackupCreateCheckWords = e("identity/reset-account-create-check-words")
export const submitSyncIdentity = e("identity/submit-sync-identity")
export const cancelSyncDevice = e("identity/device-sync-cancel")
export const createIdentityInvitationLink = e("identity/create-identity-invitation-link")
export const approveIdentityInvitedDevice = e("identity/approve-identity-invited-device")
export const rejectIdentityInvitedDevice = e("identity/reject-identity-invited-device")
export const fetchSecretPhraseCmd = e("identity/fetch-secret-phrase-cmd")
export const clearSecretPhraseCmd = e("identity/clean-secret-phrase-cmd")
export const migrateRecoveryPhraseCmd = e("identity/migrate-recovery-phrase-cmd")
export const migrateRecoveryPhraseDeclineCmd = e("identity/migrate-recovery-phrase-decline-cmd")
export const migrateRecoveryPhraseResetFormCmd = e(
"identity/migrate-recovery-phrase-reset-form-cmd",
)
export const fetchPrivateProfileStatsCmd = e("identity/fetch-private-profile-stats-cmd")
export const createIdentityUsernameCmd = e("identity/create-identity-username")
export const editIdentityUsernameCmd = e("identity/edit-identity-username")
export const verifyIdentityUsernameCmd = e("identity/verify-identity-username")
export const setIdentityProfile = e("identity/set-profile")
export const askIdentityLoad = e("identity/ask-identity-load")
export const identityLoggedOut = e("identity/logged-out")
export const fetchMyContactInvitationCmd = e("identity/fetch-my-contact-invitation-cmd")
export const removeLinkedDevice = e("identity/remove-linked-device")
export const updateUserSettingsCmd = e("identity/update-user-settings")
export const getIdentityInitialState = identitySlice.getInitialState
export const identityReducerBase = identitySlice.reducer