refactor(AvatarName): remove AvatarName class

This commit is contained in:
Christopher Astfalk
2021-05-25 18:49:07 +02:00
parent 1ad142d57d
commit efc624dba4
20 changed files with 90 additions and 47 deletions
+9 -1
View File
@@ -34,6 +34,7 @@ import {
selectLocalChat
} from '../bundles/localChat'
import {
addMissing,
selectAvatarNameById,
selectOwnAvatarName,
getFullNameString,
@@ -916,7 +917,14 @@ export function startNewIMChat (chatType, targetId, name) {
try {
name = getNameString(selectAvatarNameById(getState(), targetId.toString()))
} catch (error) {
console.error(error)
if (name) {
dispatch(addMissing({
id: targetId,
fallback: name
}))
} else {
console.error(error)
}
}
}
+7
View File
@@ -1060,6 +1060,13 @@ describe('save, loading and sending IMs', () => {
expect(store.getActions()).toEqual([
// Personal
{
type: 'names/addMissing',
payload: {
id: 'f2373437-a2ef-4435-82b9-68d283538bb2',
fallback: 'Tester FuryTest'
}
},
{
type: 'im/create',
payload: {
+4 -5
View File
@@ -4,6 +4,7 @@ import {
displayNamesStartLoading,
displayNamesLoaded,
selectNames,
selectIdOfNamesToLoad,
selectDisplayNamesURL,
selectOwnAvatarName,
selectAvatarNameById,
@@ -82,12 +83,10 @@ export function doHandleFriendOnlineStateChange (msg) {
export function getDisplayName () {
return (dispatch, getState) => {
const names = selectNames(getState())
const namesToLoad = selectIdOfNamesToLoad(getState())
const toLoad = Object.keys(names).filter(id => !names[id].willHaveDisplayName())
if (toLoad.length > 0) {
dispatch(loadDisplayNames(toLoad))
if (namesToLoad.length > 0) {
dispatch(loadDisplayNames(namesToLoad))
}
}
}
+11 -3
View File
@@ -33,7 +33,15 @@ import {
// Actions for the session of an avatar
// Logon the user. It will post using fetch to the server.
/**
* Logon the user. It will post using fetch to the server.
* @param {import('../bundles/names').MinimalAvatarName} avatarName Avatar Name
* @param {string} password Password of the avatar.
* @param {import('../types/viewer').Grid} grid Grid info
* @param {boolean} save Should the avatar be saved.
* @param {boolean} isNew Is this avatar new. False if this avatar was saved.
* @returns {import('../store/configureStore').AppThunk}
*/
export function login (avatarName, password, grid, save, isNew) {
return async (dispatch, getState, extra) => {
if (selectIsLoggedIn(getState())) throw new Error('There is already an avatar logged in!')
@@ -61,8 +69,8 @@ export function login (avatarName, password, grid, save, isNew) {
const circuit = import('../network/circuit')
const body = grid.isLLSDLogin
? await loginWithLLSD(viewerData, avatarName.first, avatarName.last, finalPassword)
: await loginWithXmlRpc(viewerData, avatarName.first, avatarName.last, finalPassword)
? await loginWithLLSD(viewerData, avatarName.firstName, avatarName.lastName, finalPassword)
: await loginWithXmlRpc(viewerData, avatarName.firstName, avatarName.lastName, finalPassword)
if (body.login !== 'true') {
dispatch(loginFailed({ error: body.message }))
+2 -1
View File
@@ -25,6 +25,7 @@ import {
selectSavedGrids,
selectSavedGridsAreLoaded
} from '../bundles/account'
import { getFullNameString } from '../bundles/names'
import { selectIsLoggedIn } from '../bundles/session'
import { createCryptoStore, getUserDatabaseName, startSyncing } from '../store/db'
@@ -45,7 +46,7 @@ export function saveAvatar (name, agentId, grid) {
return cryptoStore.withIdPrefix('avatars/').add({
dataSaveId: uuid(),
avatarIdentifier,
name: name.getFullName(),
name: getFullNameString(name),
grid: gridName
})
}
+2 -2
View File
@@ -10,7 +10,7 @@ import {
isSignedIn
} from './viewerAccount'
import AvatarName from '../avatarName'
import { parseNameString } from '../bundles/names'
let localDB
let remoteDB
@@ -291,7 +291,7 @@ describe('avatars', () => {
const avatarIdentifier = v4()
const result = await store.dispatch(saveAvatar(
new AvatarName('Tester'),
parseNameString('Tester'),
avatarIdentifier,
'Second Life'
))
+8 -6
View File
@@ -1,6 +1,7 @@
import { createSlice, createSelector, PayloadAction, Action } from '@reduxjs/toolkit'
import { RootState } from '../store/configureStore'
import type { LoginAction } from './session'
import { AvatarData, SavedAvatarData, Grid, HoodieObject } from '../types/viewer'
// Reducer for viewer-account and state
@@ -100,13 +101,14 @@ const accountSlice = createSlice({
},
extraReducers: {
'session/login' (state, action: PayloadAction<any>) {
if (!action.payload.save) { // Anonym
'session/login' (state, action: PayloadAction<LoginAction>) {
const { save, grid, name, avatarIdentifier, dataSaveId } = action.payload
if (!save) { // Anonym
state.anonymAvatarData = {
grid: action.payload.grid.name,
name: action.payload.name.getFullName(),
avatarIdentifier: action.payload.avatarIdentifier,
dataSaveId: action.payload.dataSaveId
grid: grid.name,
name: name.firstName + ' ' + name.lastName,
avatarIdentifier,
dataSaveId
}
}
},
+23 -7
View File
@@ -39,10 +39,13 @@ import {
NotificationTypes
} from '../types/chat'
export interface AvatarName {
id: string,
export interface MinimalAvatarName {
firstName: string,
lastName: string,
lastName: string
}
export interface AvatarName extends MinimalAvatarName {
id: string,
displayName: string,
isDisplayNameDefault: boolean,
didLoadDisplayName: boolean,
@@ -153,8 +156,8 @@ const nameSlice = createSlice({
[login.type] (state, action: PayloadAction<LoginAction>) {
namesAdapter.addOne(state.names, {
id: action.payload.uuid,
firstName: action.payload.name.first,
lastName: action.payload.name.last,
firstName: action.payload.name.firstName,
lastName: action.payload.name.lastName,
displayName: '',
isDisplayNameDefault: false,
didLoadDisplayName: false,
@@ -351,6 +354,19 @@ export const selectAvatarDisplayName = (state: RootState, id: string): string =>
return getDisplayName(name)
}
export const selectIdOfNamesToLoad = createSelector(
[
selectNames
],
names => Object.values(names || {})
.filter(name => name && !(
name.didLoadDisplayName ||
name.isLoadingDisplayName ||
name.displayName.length > 0
))
.map(name => name!.id)
)
export function selectDisplayNamesURL (state: RootState): string {
return state.names.getDisplayNamesURL
}
@@ -401,7 +417,7 @@ export function parseNameString (name: string, last?: string): {
}
}
export function getNameString (name: AvatarName): string {
export function getNameString (name: MinimalAvatarName & { id: string }): string {
if (
name.lastName.length === 0 ||
name.lastName === 'Resident' ||
@@ -412,7 +428,7 @@ export function getNameString (name: AvatarName): string {
return `${name.firstName} ${name.lastName}`
}
export function getFullNameString (name: AvatarName): string {
export function getFullNameString (name: MinimalAvatarName): string {
return name.firstName + ' ' + name.lastName
}
+6 -3
View File
@@ -3,7 +3,7 @@
import { createSlice, createSelector, PayloadAction, Action } from '@reduxjs/toolkit'
import { selectIsSignedIn, selectSavedAvatars, selectAnonymAvatarData } from './account'
import AvatarName from '../avatarName'
import type { MinimalAvatarName } from './names'
import { RootState } from '../store/configureStore'
import { LocalChatMessage } from '../types/chat'
@@ -15,7 +15,10 @@ const sessionSlice = createSlice({
initialState: getDefaultState(),
reducers: {
startLogin (state, action: PayloadAction<{ name: AvatarName, grid: Grid, sync: boolean }>) {},
startLogin (
state,
action: PayloadAction<{ name: MinimalAvatarName, grid: Grid, sync: boolean }>
) {},
// didLogin
login (state, action: PayloadAction<LoginAction>) {
@@ -177,7 +180,7 @@ export interface LoginAction {
/**
* Name of the logged in avatar
*/
name: AvatarName
name: MinimalAvatarName
/**
* Should the avatar and its data be saved and synced?
*/
-1
View File
@@ -5,7 +5,6 @@ import thunk from 'redux-thunk'
import { render, fireEvent } from '@testing-library/react'
import ChatDialog from './chatDialog'
import AvatarName from '../avatarName'
function configureStore (state = {}) {
const store = configureMockStore([thunk])
+1 -1
View File
@@ -8,7 +8,7 @@ import configureStore from '../store/configureStore'
import { LocalChatSourceType } from '../types/chat'
jest.mock('../reactors/index.js', () => [])
jest.mock('../reactors/index.ts', () => [])
function getTimeString (timeSting) {
const date = new Date(timeSting)
+6 -3
View File
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'react'
import AvatarName from '../../avatarName'
import { parseNameString, getNameString } from '../../bundles/names'
import { useAutoFocus } from '../../hooks/utils'
@@ -11,6 +11,9 @@ export default function AvatarLogin ({ avatar, grid, isLoggingIn, onLogin, isSel
}, [isSelected])
const doAutoFocus = useAutoFocus()
const name = parseNameString(avatar.name)
name.id = avatar.avatarIdentifier
const nameString = getNameString(name)
if (!isSelected) {
return (
@@ -23,7 +26,7 @@ export default function AvatarLogin ({ avatar, grid, isLoggingIn, onLogin, isSel
>
<button className='flex flex-col text-white btn--transparent focus:outline-none'>
<h2 className='block m-1 text-center'>
<span className='text-2xl'>{new AvatarName(avatar.name).getDisplayName()}</span>
<span className='text-2xl'>{nameString}</span>
<span className='inline-block ml-3'>@{grid.name}</span>
</h2>
@@ -49,7 +52,7 @@ export default function AvatarLogin ({ avatar, grid, isLoggingIn, onLogin, isSel
onSubmit={onSubmit}
>
<h2 className='block m-1 text-center'>
<span className='text-2xl'>{new AvatarName(avatar.name).getDisplayName()}</span>
<span className='text-2xl'>{nameString}</span>
<span className='inline-block ml-3'>@{grid.name}</span>
</h2>
+2 -2
View File
@@ -2,6 +2,7 @@ import { useState, useEffect, Fragment } from 'react'
import { useHistory } from 'react-router-dom'
import { selectSavedAvatars, selectGridsByName } from '../../bundles/account'
import { parseNameString } from '../../bundles/names'
import { login } from '../../actions/sessionActions'
import { useSelector, useDispatch } from '../../hooks/store'
@@ -9,7 +10,6 @@ import { useSelector, useDispatch } from '../../hooks/store'
import LoginNewAvatar from './newAvatarLogin'
import AvatarLogin from './avatarLogin'
import SignIn from './signIn'
import AvatarName from '../../avatarName'
export default function LoginForm ({ isSignedIn }) {
const dispatch = useDispatch()
@@ -99,7 +99,7 @@ export default function LoginForm ({ isSignedIn }) {
return
}
const avatarName = new AvatarName(name)
const avatarName = parseNameString(name)
setIsLoggingIn(name)
await dispatch(login(avatarName, password, grid, save, isNew))
+1 -1
View File
@@ -13,7 +13,7 @@ import {
selectAvatarDisplayName
} from '../bundles/names'
jest.mock('../reactors/index.js', () => [])
jest.mock('../reactors/index.ts', () => [])
/**
* Create a Store with names.
@@ -2,13 +2,13 @@ import { createSelector } from 'reselect'
import { getDisplayName } from '../actions/friendsActions'
import { selectNames } from '../bundles/names'
import { selectIdOfNamesToLoad } from '../bundles/names'
export const loadNames = createSelector(
[
selectNames
selectIdOfNamesToLoad
],
names => Object.values(names).some(name => !name.willHaveDisplayName())
namesToLoad => namesToLoad.length > 0
? getDisplayName()
: null
)
+1 -4
View File
@@ -14,7 +14,6 @@ import configureReactors from './configureReactors'
import { createLocalDB, createCryptoStore, createRemoteDB } from './db'
import { proxyFetch, fetchLLSD } from './llsdFetch'
import AvatarName from '../avatarName'
import type Circuit from '../network/circuit'
export type RootState = ReturnType<typeof rootReducer>
@@ -142,9 +141,7 @@ export function createStoreCore (
extraArgument: ExtraArguments
) {
const serializableCheck: SerializableStateInvariantMiddlewareOptions = {
isSerializable: value => isPlain(value) ||
value instanceof Uint8Array ||
value instanceof AvatarName
isSerializable: value => isPlain(value) || value instanceof Uint8Array
}
const middleware = getDefaultMiddleware({
thunk: {
+4 -4
View File
@@ -5,10 +5,10 @@ import auth from 'pouchdb-authentication'
import hoodieApi from 'pouchdb-hoodie-api'
import { NIL } from 'uuid'
import AvatarName from './avatarName'
import connectCircuit from './actions/connectCircuit'
import { isSignedIn, loadSavedAvatars, loadSavedGrids } from './actions/viewerAccount'
import { signInStatus } from './bundles/account'
import { parseNameString } from './bundles/names'
import { startLogin, login } from './bundles/session'
import { createExtraArgument, createStoreCore } from './store/configureStore'
@@ -345,7 +345,7 @@ async function setStateToConnectedToGrid (
store: ReturnType<typeof createStoreCore>,
extraArgument: ReturnType<typeof createExtraArgument>
) {
const name = new AvatarName('AndromedaViewerTester')
const name = parseNameString('AndromedaViewerTester')
const grid = {
_id: 'second_life',
name: 'Second Life',
@@ -364,8 +364,8 @@ async function setStateToConnectedToGrid (
sessionInfo: {
login: 'true',
andromedaSessionId: 'e95ecf9b-9104-4d6b-9a4d-09de71e956e8',
first_name: `"${name.first}"`,
last_name: name.last,
first_name: `"${name.firstName}"`,
last_name: name.lastName,
account_type: 'Base',
account_level_benefits: {
lastname_change_allowed: '',