diff --git a/src/hub.js b/src/hub.js index 89c03be300ad7bf9122ef0837cb6546f11a05ea0..abc6f392813bc5c7be90c5cdc0671d9ca289e4c2 100644 --- a/src/hub.js +++ b/src/hub.js @@ -90,7 +90,7 @@ import { inGameActions, config as inputConfig } from "./input-mappings"; import registerTelemetry from "./telemetry"; import Store from "./storage/store"; -import { generateDefaultProfile } from "./utils/identity.js"; +import { generateDefaultProfile, generateRandomName } from "./utils/identity.js"; import { getAvailableVREntryTypes } from "./utils/vr-caps-detect.js"; import ConcurrentLoadDetector from "./utils/concurrent-load-detector.js"; @@ -117,6 +117,11 @@ concurrentLoadDetector.start(); // Always layer in any new default profile bits store.update({ profile: { ...generateDefaultProfile(), ...(store.state.profile || {}) } }); +// Regenerate name to encourage users to change it. +if (!store.state.profile.has_changed_name) { + store.update({ profile: { display_name: generateRandomName() } }); +} + async function exitScene() { hubChannel.disconnect(); const scene = document.querySelector("a-scene"); @@ -226,7 +231,7 @@ function mountUI(scene) { const forcedVREntryType = qs.vr_entry_type || null; const enableScreenSharing = qsTruthy("enable_screen_sharing"); const htmlPrefix = document.body.dataset.htmlPrefix || ""; - const showProfileEntry = !store.state.profile.has_saved_profile; + const showProfileEntry = !store.state.profile.has_changed_name; // TODO: Refactor to avoid using return value /* eslint-disable react/no-render-return-value */ diff --git a/src/react-components/profile-entry-panel.js b/src/react-components/profile-entry-panel.js index af1c7382f9ecb56b5a58bec0d623f9b35aa97562..0322c551fcd7e739b508b19becf3559a81f4c3e1 100644 --- a/src/react-components/profile-entry-panel.js +++ b/src/react-components/profile-entry-panel.js @@ -14,10 +14,8 @@ class ProfileEntryPanel extends Component { constructor(props) { super(props); - this.state = { - display_name: this.props.store.state.profile.display_name, - avatar_id: this.props.store.state.profile.avatar_id - }; + const { display_name, avatar_id } = this.props.store.state.profile; + this.state = { display_name, avatar_id }; this.props.store.addEventListener("statechanged", this.storeUpdated); } @@ -28,11 +26,12 @@ class ProfileEntryPanel extends Component { saveStateAndFinish = e => { e.preventDefault(); + const { has_changed_name, display_name } = this.props.store.state.profile; + const hasChangedName = !has_changed_name && this.state.display_name !== display_name; this.props.store.update({ profile: { - has_saved_profile: true, - display_name: this.state.display_name, - avatar_id: this.state.avatar_id + has_changed_name: hasChangedName, + ...this.state } }); this.props.finished(); diff --git a/src/storage/store.js b/src/storage/store.js index 2c79a06604a08b0e1a72e1b3fca2a2d4264d80c5..299ff0c4050916e7e19af35ceaa59c791d19b4c5 100644 --- a/src/storage/store.js +++ b/src/storage/store.js @@ -1,5 +1,6 @@ import uuid from "uuid/v4"; import { Validator } from "jsonschema"; +import { merge } from "lodash"; const LOCAL_STORE_KEY = "___mozilla_duck"; const STORE_STATE_CACHE_KEY = Symbol(); @@ -16,7 +17,7 @@ export const SCHEMA = { type: "object", additionalProperties: false, properties: { - has_saved_profile: { type: "boolean" }, + has_changed_name: { type: "boolean" }, display_name: { type: "string", pattern: "^[A-Za-z0-9-]{3,32}$" }, avatar_id: { type: "string" } } @@ -57,7 +58,7 @@ export default class Store extends EventTarget { throw new Error("Store id is immutable."); } - const finalState = { ...this.state, ...newState }; + const finalState = merge(this.state, newState); const isValid = validator.validate(finalState, SCHEMA).valid; if (!isValid) { diff --git a/src/utils/identity.js b/src/utils/identity.js index e4d79896c1dce8e8175fe0e6420f1c88aac2a858..4443ffb01295daf6bc5fdf5865d7b04826862da9 100644 --- a/src/utils/identity.js +++ b/src/utils/identity.js @@ -167,13 +167,15 @@ function selectRandom(arr) { return arr[Math.floor(Math.random() * arr.length)]; } +export function generateRandomName() { + return `${selectRandom(names)}-${Math.floor(10000 + Math.random() * 10000)}`; +} + export const avatarIds = avatars.map(av => av.id); export function generateDefaultProfile() { - const name = selectRandom(names); return { - has_saved_profile: false, - display_name: name.replace(/^./, name[0].toUpperCase()), + has_changed_name: false, avatar_id: selectRandom(avatarIds) }; }