Skip to content
Snippets Groups Projects
Unverified Commit 6704cfb9 authored by Brian Peiris's avatar Brian Peiris Committed by GitHub
Browse files

Merge pull request #70 from mozilla/feature/react-name-entry

storage based name entry with validation
parents fcd5838f 3b603398
No related branches found
No related tags found
No related merge requests found
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { VR_DEVICE_AVAILABILITY } from "../utils/vr-caps-detect.js";
import { SCHEMA } from "../storage/store";
const ENTRY_STEPS = {
start: "start",
......@@ -44,34 +45,12 @@ const DaydreamEntryButton = (props) => (
</button>
);
class ProfileEntryPanel extends Component {
static propTypes = {
store: PropTypes.object
};
state = {
name: "",
}
nameChanged = (ev) => {
this.setState({ name: ev.target.value });
}
render() {
return (
<div>
<input type="text" value={this.state.name} onChange={this.nameChanged}/>
</div>
);
}
}
const AutoExitWarning = (props) => (
<div>
<p>
Exit in <span>{props.secondsRemaining}</span>
</p>
<button onClick={props.onCancel}>
Cancel
</button>
......@@ -94,10 +73,10 @@ class UIRoot extends Component {
static propTypes = {
enterScene: PropTypes.func,
availableVREntryTypes: PropTypes.object,
store: PropTypes.object,
concurrentLoadDetector: PropTypes.object,
disableAutoExitOnConcurrentLoad: PropTypes.bool
};
disableAutoExitOnConcurrentLoad: PropTypes.bool,
store: PropTypes.object,
}
state = {
entryStep: ENTRY_STEPS.start,
......@@ -127,7 +106,7 @@ class UIRoot extends Component {
this.props.concurrentLoadDetector.addEventListener("concurrentload", this.onConcurrentLoad);
}
setupTestTone = () => {
setupTestTone = () => {
const toneClip = document.querySelector("#test-tone");
const toneLength = 1800;
const toneDelay = 5000;
......@@ -317,20 +296,24 @@ class UIRoot extends Component {
}
}
this.props.enterScene(mediaStream);
this.stopTestTone();
this.props.enterScene(this.state.mediaStream);
this.setState({ entryStep: ENTRY_STEPS.finished });
}
saveName = (e) => {
e.preventDefault();
this.props.store.update({ profile: { display_name: this.nameInput.value } });
}
render() {
const entryPanel = this.state.entryStep === ENTRY_STEPS.start
const entryPanel = this.state.entryStep === ENTRY_STEPS.start
? (
<div>
<TwoDEntryButton onClick={this.enter2D}/>
{ this.props.availableVREntryTypes.generic !== VR_DEVICE_AVAILABILITY.no && <GenericEntryButton onClick={this.enterVR}/> }
{ this.props.availableVREntryTypes.gearvr !== VR_DEVICE_AVAILABILITY.no && <GearVREntryButton onClick={this.enterGearVR}/> }
{ this.props.availableVREntryTypes.daydream !== VR_DEVICE_AVAILABILITY.no && <DaydreamEntryButton onClick={this.enterDaydream}/> }
<ProfileEntryPanel profileName={ this.state.profileNamePending }/>
</div>
) : null;
......@@ -364,12 +347,31 @@ class UIRoot extends Component {
</div>
) : null;
const nameEntryPanel = (
<div>
Name Entry
<form onSubmit={this.saveName}>
<label>Name:
<input
defaultValue={this.props.store.state.profile.display_name}
required pattern={SCHEMA.definitions.profile.properties.display_name.pattern}
title="Alphanumerics and hyphens. At least 3 characters, no more than 32"
ref={inp => this.nameInput = inp}/>
</label>
<input type="submit" value="Save" />
</form>
</div>
);
const overlay = this.isWaitingForAutoExit() ?
(<AutoExitWarning secondsRemaining={this.state.secondsRemainingBeforeAutoExit} onCancel={this.endAutoExitTimer} />) :
(<div>
{entryPanel}
{micPanel}
{audioSetupPanel}
(
<div>
{entryPanel}
{micPanel}
{audioSetupPanel}
{nameEntryPanel}
</div>
);
......
......@@ -19,3 +19,8 @@
left: 0;
position: absolute;
}
.rs-base {
top: auto;
bottom: 20px;
}
......@@ -121,6 +121,11 @@ async function exitScene() {
document.body.removeChild(scene);
}
function setNameTagFromStore() {
const myNametag = document.querySelector("#player-rig .nametag");
myNametag.setAttribute("text", "value", store.state.profile.display_name);
}
async function enterScene(mediaStream) {
const qs = queryString.parse(location.search);
const scene = document.querySelector("a-scene");
......@@ -139,8 +144,8 @@ async function enterScene(mediaStream) {
playerRig.setAttribute("virtual-gamepad-controls", {});
}
const myNametag = document.querySelector("#player-rig .nametag");
myNametag.setAttribute("text", "value", store.state.profile.display_name);
setNameTagFromStore();
store.subscribe(setNameTagFromStore);
const avatarScale = parseInt(qs.avatarScale, 10);
......@@ -202,9 +207,9 @@ function mountUI() {
enterScene,
exitScene,
concurrentLoadDetector,
disableAutoExitOnConcurrentLoad
disableAutoExitOnConcurrentLoad,
store,
}} />, document.getElementById("ui-root"));
document.getElementById("loader").style.display = "none";
});
}
......
......@@ -7,7 +7,7 @@ const validator = new Validator();
// Durable (via local-storage) schema-enforced state that is meant to be consumed via forward data flow.
// (Think flux but with way less incidental complexity, at least for now :))
const SCHEMA = {
export const SCHEMA = {
id: "/MozillaDuckStore",
definitions: {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment