diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 60ad77cc..a15ea87b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,6 +5,8 @@ on: [push, pull_request]
jobs:
ci-checks:
runs-on: ubuntu-latest
+ env:
+ NODE_OPTIONS: '--max_old_space_size=4096'
container:
image: node:12.18
diff --git a/src/actions/authActions.js b/src/actions/authActions.js
index a77bb285..e11c65ae 100644
--- a/src/actions/authActions.js
+++ b/src/actions/authActions.js
@@ -5,7 +5,7 @@ import * as types from "../constants/ActionTypes";
*
* @param {obj} user User data from the firebase auth obj
*
- * @returns reducer action obj with type: LOGIN and user obj
+ * @returns {object} reducer action obj with type: LOGIN and user obj
*/
export function login(user) {
return { type: types.LOGIN, user };
@@ -14,12 +14,19 @@ export function login(user) {
/**
* Sends a signal to the reducer to logout the current user
*
- * @returns reducer action obj with type: LOGOUT
+ * @returns {object} reducer action obj with type: LOGOUT
*/
export function logout() {
return { type: types.LOGOUT };
}
+/**
+ * Sends a signal to the reducer to refresh the token
+ *
+ * @param {object} token
+ *
+ * @returns {object} reducer action object with type: REFRESH_TOKEN and token obj
+ */
export function refreshToken(token) {
return { type: types.REFRESH_TOKEN, token };
}
diff --git a/src/actions/collectionActions.js b/src/actions/collectionActions.js
index 1b91b3b4..11d1e83c 100644
--- a/src/actions/collectionActions.js
+++ b/src/actions/collectionActions.js
@@ -2,12 +2,19 @@ import * as types from "../constants/ActionTypes";
export const collectRef = "/apiv1/collections";
-export function asyncCollections(id) {
+
+/**
+ * Fetch the list of the user collection asynchronously
+ * Use when user login or added a new collection
+ *
+ * @param {*} uid A JWT token to authenticate with the backend
+ */
+export function asyncCollections(uid) {
// fetch user's collections
return (dispatch) => {
- if (id) {
+ if (uid) {
let userCollections = [];
- fetch(collectRef, {headers: {"x-access-token": id}}).then((data) => {
+ fetch(collectRef, {headers: {"x-access-token": uid}}).then((data) => {
data.json().then((data) => {
data.forEach((doc) => {
userCollections.push(doc);
@@ -19,10 +26,23 @@ export function asyncCollections(id) {
};
}
+/**
+ * Sends a signal to the reducer to sync the user collections
+ *
+ * @param {object} payload List of user collections
+ *
+ * @returns {object} reducer action obj with type SYNC_COLLECTIONS with payload
+ */
export function syncCollections(payload) {
- return { type: types.SYNC_CLASSES, payload: payload };
+ return { type: types.SYNC_COLLECTIONS, payload: payload };
}
+/**
+ * Fetch the specific collection specify by user
+ *
+ * @param {string} collectionID Collection id
+ * @param {*} uid A JWT token to authenticate with the backend
+ */
export function asyncCollection(collectionID, uid) {
// fetch projects in collection
return (dispatch) => {
@@ -62,13 +82,27 @@ export function asyncCollection(collectionID, uid) {
};
}
+/**
+ * Sends a signal to the reducer to load the retrieved collection
+ *
+ * @param {object} payload Data of retrieved collection
+ *
+ * @returns {object} reducer action obj with type: SYNC_COLLECTION and payload
+ */
export function syncCollection(payload) {
- return { type: types.SYNC_CLASS, payload: payload };
+ return { type: types.SYNC_COLLECTION, payload: payload };
}
-export function deleteCollection(id, name = null, uid) {
+/**
+ * Sends a signal to the reducer to delete the specific collection of user
+ *
+ * @param {string} collectionID Collection ID
+ * @param {string} name Name of the collection if exists
+ * @param {*} uid A JWT token to authenticate with the backend
+ */
+export function deleteCollection(collectionID, name = null, uid) {
return (dispatch) => {
- name = (name ? name : id);
+ name = (name ? name : collectionID);
if (window.confirm(`Are you sure you want to delete collection "${name}"?`)) {
// Delete Document
@@ -77,12 +111,14 @@ export function deleteCollection(id, name = null, uid) {
console.error(`Error deleting collection ${name}: ${resp.statusText}`);
return;
}
- dispatch({ type: types.DELETE_CLASS, id: id });
+ dispatch({ type: types.DELETE_COLLECTION, id: collectionID });
});
}
};
}
+
/**
+ * Creates a new collection
*
* @param {string} name The name of the collection to be created
* @param {*} uid A JWT token to authenticate with the backend
diff --git a/src/actions/courseActions.js b/src/actions/courseActions.js
index c52f4eb4..657de158 100644
--- a/src/actions/courseActions.js
+++ b/src/actions/courseActions.js
@@ -6,7 +6,7 @@ import * as sceneActions from "./sceneActions";
const courseRef = "/apiv1/courses/";
const header = { headers: { "content-type": "application/json" } };
-let noLessons = {
+const noLessons = {
name: "",
id: -1,
prompt: "There are no lessons in this course",
@@ -19,9 +19,12 @@ const problem = {
code: ""
};
-/**
+/*
* Course Actions
*/
+/**
+ * Fetch all the courses available
+ */
export function fetchCourses() {
return (dispatch) => {
fetch(courseRef, header)
@@ -42,10 +45,22 @@ export function fetchCourses() {
};
}
+/**
+ * Sends a signal to the reducer to synchronize the courses
+ *
+ * @param {*} payload List of courses retrieved
+ *
+ * @returns reducer action object with type: SYNC_COURSE and payload
+ */
export function syncCourses(payload) {
return { type: types.SYNC_COURSES, payload: payload };
}
+/**
+ * Fetch specific course
+ *
+ * @param {string} courseId id of the course getting
+ */
export function fetchCourse(courseId) {
return (dispatch) => {
fetch(courseRef + courseId, header)
@@ -84,16 +99,23 @@ export function fetchCourse(courseId) {
};
}
+/**
+ * Sends signal to the reducer to load the course retrieved
+ *
+ * @param {*} course Data of course retrieved
+ * @returns {object} reducer action obj with type: LOAD_COURSE and payload
+ */
export function loadCourse(course) {
- return {
- type: types.LOAD_COURSE,
- payload: course
- };
+ return { type: types.LOAD_COURSE, payload: course };
}
-/**
+/*
* Lesson Actions
*/
+/**
+ * Fetch the lesson that is supplied by the parameter.
+ * @param {*} json Lesson data
+ */
export function fetchLesson(json) {
return (dispatch) => {
dispatch(loadLesson(json));
@@ -106,10 +128,21 @@ export function fetchLesson(json) {
}
/**
- * Frontend disables option if out of bounds
+ * Sends signal to the reducer to load a new lesson supplied by parameter
+ *
+ * @param {object} lesson Lesson data
+ * @returns reducer action obj with type: LOAD_LESSON and payload: lesson
+ */
+export function loadLesson(lesson) {
+ return { type: types.LOAD_LESSON, payload: lesson };
+}
+
+/**
+ * Increment the lesson index and load the next lesson.
+ * Frontend disables option if out of bounds
*
- * @param {*} currentIndex !!!DESCRIPTION NEEDED!!!
- * @param {*} next !!!DESCRIPTION NEEDED!!!
+ * @param {number} currentIndex current index of the course
+ * @param {object} next Object of lesson to be load next
*/
export function nextLesson(currentIndex, next) {
return (dispatch) => {
@@ -119,10 +152,11 @@ export function nextLesson(currentIndex, next) {
}
/**
- * Frontend disables option if out of bounds
+ * Decrement the lesson index and load the previous lesson.
+ * Frontend disables option if out of bounds
*
- * @param {*} currentIndex !!!DESCRIPTION NEEDED!!!
- * @param {*} prev !!!DESCRIPTION NEEDED!!!
+ * @param {number} currentIndex current index of the course
+ * @param {object} prev Object of lesson to be load previous
*/
export function previousLesson(currentIndex, prev) {
return (dispatch) => {
@@ -131,18 +165,14 @@ export function previousLesson(currentIndex, prev) {
};
}
+/**
+ * Sends signal to the reducer to update the current index of the Course
+ *
+ * @param {number} newIndex New index to be set
+ * @returns {object} reducer action obj with type: SET_INDEX and payload: newIndex
+ */
export function setCurrentIndex(newIndex) {
- return {
- type: types.SET_INDEX,
- payload: newIndex
- };
-}
-
-export function loadLesson(lesson) {
- return {
- type: types.LOAD_LESSON,
- payload: lesson
- };
+ return { type: types.SET_INDEX, payload: newIndex };
}
export default {
diff --git a/src/actions/editorActions.js b/src/actions/editorActions.js
index fd0842fb..107bc37c 100644
--- a/src/actions/editorActions.js
+++ b/src/actions/editorActions.js
@@ -8,7 +8,8 @@ const sceneRef = "/apiv1/scenes";
* Sends a signal to the reducer to render the scene
*
* @param {string} text Text from the Ace Editor component
- *
+ * @param {*} uid A JWT token to authenticate with the backend
+ *
* @returns reducer action obj with action type and text
*/
export function render(text, uid) {
@@ -19,6 +20,7 @@ export function render(text, uid) {
* Sends a signal to the reducer to refresh with the given text
*
* @param {string} text Text from the Ace Editor component
+ * @param {*} uid A JWT token to authenticate with the backend
*
* @returns reducer action obj with action type and text
*/
@@ -36,8 +38,11 @@ export function recover() {
}
/**
- * This does an async fetch to Firebase to grab the scene, then
+ * This does an async fetch to backend to grab the scene, then
* dispatches the necessary functions to update the state.
+ *
+ * @param {string} id scene id
+ * @param {*} uid A JWT token to authenticate with the backend
*/
export function fetchScene(id, uid = "anon") {
return (dispatch) => { // Return a func that dispatches events after async
@@ -89,20 +94,14 @@ export function fetchScene(id, uid = "anon") {
*
* @returns reducer action obj with action type
*/
-
export function updateSavedText(savedText){
return {type: types.EDITOR_UPDATE_SAVEDTEXT, savedText};
}
-export function addPassword(payload) {
- return { type: types.ADD_PW, payload };
-}
-
export default {
render,
refresh,
recover,
fetchScene,
- addPassword,
updateSavedText,
};
\ No newline at end of file
diff --git a/src/actions/projectActions.js b/src/actions/projectActions.js
index 5c2a2e16..a0592947 100644
--- a/src/actions/projectActions.js
+++ b/src/actions/projectActions.js
@@ -3,11 +3,16 @@ import * as types from "../constants/ActionTypes";
const sceneRef = "/apiv1/scenes";
const previewRef = "/apiv1/preview/id";
-export function asyncUserProj(id) {
+/**
+ * Retrieved the list of user scenes
+ *
+ * @param {*} uid A JWT token to authenticate with the backend
+ */
+export function asyncUserProj(uid) {
// fetch user's project
return (dispatch) => {
- if (id) {
- fetch(`${sceneRef}/`, {headers: {"x-access-token": id}}).then((response) =>{
+ if (uid) {
+ fetch(`${sceneRef}/`, {headers: {"x-access-token": uid}}).then((response) =>{
if(response.status === 200){
response.json().then((json) =>{
json.forEach(element => {
@@ -21,10 +26,21 @@ export function asyncUserProj(id) {
};
}
+
+/**
+ * Sends signal to the reducer to sync the user project
+ *
+ * @param {*} payload list of user projects
+ *
+ * @returns reducer action obj with type: SYNC_USER_PROJ wiht payload
+ */
export function syncUserProj(payload) {
return { type: types.SYNC_USER_PROJ, payload: payload };
}
+/**
+ * Fetch a eample scenes from the backend
+ */
export const asyncExampleProj = () => {
// fetch example projects
return (dispatch) => {
@@ -41,10 +57,24 @@ export const asyncExampleProj = () => {
};
};
+
+/**
+ * Sends signal to the reducer to sync the example project
+ * @param {*} payload List of the example project
+ *
+ * @returns reducer action obj with type: SYNC_EXAMP_PROJ with payload
+ */
export function syncExampleProj(payload) {
return { type: types.SYNC_EXAMP_PROJ, payload: payload };
}
+/**
+ * Delete the specify user project
+ *
+ * @param {*} uid A JWT token to authenticate with the backend
+ * @param {string} id Scene id to be deleted
+ * @param {string} name Name of the scene
+ */
export function deleteProj(uid, id, name) {
return (dispatch) => {
if (window.confirm(`Are you sure you want to delete ${name}?`)) {
diff --git a/src/actions/referenceExampleActions.js b/src/actions/referenceExampleActions.js
index a6a3cb37..29da2623 100644
--- a/src/actions/referenceExampleActions.js
+++ b/src/actions/referenceExampleActions.js
@@ -25,9 +25,10 @@ const notFound = {
};
/**
- * Lesson Actions
+ * Fetch specific example scene from backend.
+ * On success, load and render the example scene
*
- * @param {*} funcName !!!DESCRIPTION NEEDED!!!
+ * @param {string} funcName Name of the example scene to retrieve
*/
export function fetchReferenceExample(funcName) {
return (dispatch) => {
@@ -60,6 +61,12 @@ export function fetchReferenceExample(funcName) {
};
}
+/**
+ * Sends a signal to the reducer to load the retrieved scene
+ *
+ * @param {object} refEx object of data of example scene
+ * @returns reducer action obj with type: LOAD_REF_EX with payload:refEx
+ */
export function loadReferenceExample(refEx) {
return {
type: types.LOAD_REF_EX,
diff --git a/src/actions/sceneActions.js b/src/actions/sceneActions.js
index 179982c2..04de974a 100644
--- a/src/actions/sceneActions.js
+++ b/src/actions/sceneActions.js
@@ -1,7 +1,7 @@
import * as types from "../constants/ActionTypes";
/**
- * This function registers the scene"s name with Redux
+ * This function registers the scene's name with Redux
*
* @param {string} name the name is given by the user or when a scene is loaded
*
@@ -12,9 +12,9 @@ export function nameScene(name) {
}
/**
- * This function registers the scene's id with Redux
+ * This function load data of scene to the redux store
*
- * @param {string} id the id of the loaded scene
+ * @param {string} data the id of the loaded scene
*
* @returns a reducer action with type:LOAD_SCENE
*/
@@ -22,80 +22,197 @@ export function loadScene(data) {
return { type: types.LOAD_SCENE, data };
}
+/**
+ * Sends a signal to the reducer to toggle the coordinate floor
+ *
+ * @returns {object} reducer action obj with type: TOGGLE_COORD_SKY
+ */
export function toggleCoordSky() {
return { type: types.TOGGLE_COORD_SKY };
}
+
+/**
+ * Sends a signal to the reducer to toggle the default light
+ *
+ * @returns {object} reducer action obj with type: TOGGLE_DEFAULT_LIGHT
+ */
export function toggleDefaultLight() {
return { type: types.TOGGLE_DEFAULT_LIGHT };
}
+
+/**
+ * Sends a signal to the reducer to toggle the floor
+ *
+ * @returns {object} reducer action obj with type: TOGGLE_FLOOR
+ */
+export function toggleFloor() {
+ return { type: types.TOGGLE_FLOOR };
+}
+
+/**
+ * Sends a signal to the reducer to toggle for light to cast shadow
+ *
+ * @returns {object} reducer action obj with type: TOGGLE_CAST_SHADOW
+ */
export function toggleCastShadow() {
return { type: types.TOGGLE_CAST_SHADOW };
}
+/**
+ * Sends a signal to the reducer to toggle for light to show light indicator
+ *
+ * @returns {object} reducer action obj with type: TOGGLE_LIGHT_INDICATOR
+ */
export function toggleLightIndicator(){
return {type: types.TOGGLE_LIGHT_INDICATOR};
}
+/**
+ * Sends a signal to the reducer to change the sky color
+ *
+ * @param {string} color Color to be change to
+ *
+ * @returns {object} reducer action obj with type: CHANGE_SKY_COLOR with color;
+ */
export function changeSkyColor(color) {
return { type: types.CHANGE_SKY_COLOR, color };
}
+/**
+ * Sends a signal to the reducer to change the sky color
+ *
+ * @param {string} color Color to be change to
+ *
+ * @returns {object} reducer action obj with type: CHANGE_FLOOR_COLOR with color;
+ */
export function changeFloorColor(color) {
return { type: types.CHANGE_FLOOR_COLOR, color };
}
-export function changeCamMode(config) {
- return { type: types.CHANGE_CAM_MODE, config };
-}
-
+/**
+ * Sends a signal to the reducer to change the position of the camera
+ *
+ * @param {number} x X Position
+ * @param {number} y Y Position
+ * @param {number} z Z Position
+ *
+ * @returns {object} reducer action obj with type: SET_CAMERA with x,y,z position
+ */
export function setCamera(x, y, z) {
return { type: types.SET_CAMERA, x, y, z };
}
-export function changePerspective() {
- return { type: types.CHANGE_PERSPECTIVE };
-}
-
+/**
+ * Sends a signal to the reducer to toggle to be view only(hide the editor) or not
+ *
+ * @returns {object} reducer action obj with type: CHANGE_VIEW
+ */
export function changeView() {
return { type: types.CHANGE_VIEW };
}
-export function toggleFloor() {
- return { type: types.TOGGLE_FLOOR };
-}
-
+/**
+ * Sends a signal to the reducer to load the settings sends by the
+ *
+ * @returns {object} reducer action obj with type:
+ */
export function loadSettings(payload) {
return { type: types.LOAD_SETTINGS, payload };
}
-export function changeSettings(payload) {
- return { type: types.CHANGE_SETTINGS, payload };
-}
-
+/**
+ * Sends a signal to the reducer to reset the settings to default
+ *
+ * @returns {object} reducer action obj with type: RESET_SETTINGS
+ */
export function resetSettings() {
return { type: types.RESET_SETTINGS };
}
+/**
+ * Sends a signal to the reducer to add the scene to the collection
+ *
+ * @param {string} payload id of collection to add scene to
+ *
+ * @returns {object} reducer action obj with type: ADD_COLLECTION with payload
+ */
export function addCollectionID(payload) {
- return { type: types.ADD_CLASSROOM, payload };
+ return { type: types.ADD_COLLECTION, payload };
}
+/**
+ * Sends a signal to the reducer to add the scene to the collection
+ *
+ * @param {string} payload id of collection to remove scene to
+ *
+ * @returns {object} reducer action obj with type: REMOVE_COLLECTION with payload
+ */
export function removeCollectionID(payload) {
- return { type: types.REMOVE_CLASSROOM, payload};
+ return { type: types.REMOVE_COLLECTION, payload};
}
+/**
+ * Sends a signal to the reducer to cahnge the description of the scene
+ *
+ * @param {string} payload description of the
+ *
+ * @returns {object} reducer action obj with type: SET_DESC with payload
+ */
export function setDesc(payload) {
return { type: types.SET_DESC, payload };
}
+/**
+ * Sends a signal to the reducer to change both name and description
+ *
+ * @returns {object} reducer action obj with type:
+ */
export function setNameDesc(payload) {
return { type: types.SET_NAME_DESC, payload };
}
+/**
+ * Sends a signal to the reducer to change the speed of movement
+ *
+ * @param {number} speed
+ * @returns
+ */
export function updateMoveSpeed(speed) {
return { type: types.UPDATE_MOVE_SPEED, speed };
}
+/*
+ * Unused functions
+ */
+/**
+ * Sends a signal to the reducer to change the settings
+ *
+ * @returns {object} reducer action obj with type: CHANGE_SETTINGS with payload
+ */
+export function changeSettings(payload) {
+ return { type: types.CHANGE_SETTINGS, payload };
+}
+
+/**
+ * Sends a signal to the reducer to change the mode of the camera
+ *
+ * @param {*} config New mode to change
+ *
+ * @returns {object} reducer action obj with type: CHANGE_CAM_MODE with config
+ */
+export function changeCamMode(config) {
+ return { type: types.CHANGE_CAM_MODE, config };
+}
+
+/**
+ * Sends a signal to the reducer to change the perspective
+ *
+ * @returns {object} reducer action obj with type: CHANGE_PERSPECTIVE
+ */
+export function changePerspective() {
+ return { type: types.CHANGE_PERSPECTIVE };
+}
+
export default {
nameScene,
loadScene,
diff --git a/src/components/collection/Collection.js b/src/components/collection/Collection.js
index 6b845615..6d6aadaf 100644
--- a/src/components/collection/Collection.js
+++ b/src/components/collection/Collection.js
@@ -30,7 +30,7 @@ function getModalStyle() {
/**
* CSS for modal
*
- * @param {*} theme !!!DESCRIPTION NEEDED!!!
+ * @param {*} theme Will use default theme if not provided
*/
const modelStyles = theme => ({
paper: {
@@ -71,6 +71,9 @@ const btnStyle = {
}
};
+/**
+ * React Component for Create Collection Modal to Navigate different options for collection
+ */
class CollectionModal extends Component {
constructor(props) {
super(props);
@@ -82,10 +85,18 @@ class CollectionModal extends Component {
};
}
+ /**
+ * Move to selected collection page when selected
+ * @param {object} selectedCollection passed the data of selected collection
+ */
handleChange = (selectedCollection) => {
window.location.assign(window.origin + "/collection/" + selectedCollection.value);
}
+ /**
+ * Handle when user deleted the selected collection
+ * @param {object} selectedCollection passed the data of selected collection
+ */
handleDelete = (selectedCollection) => {
let needsToRedirect = (this.props.openCollection === selectedCollection.label);
this.props.collectionActions.deleteCollection(selectedCollection.value, selectedCollection.label, this.props.user.uid);
@@ -96,29 +107,49 @@ class CollectionModal extends Component {
this.props.deleteCallback(selectedCollection.label);
}
+ /**
+ * Update the state with the collection name user enter in the field
+ * @param {string} name name of the state to be change
+ * @param {object} event Event interface when the onChnage event was dispatched
+ */
handleTextChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
- handleAddClassToggle = () => {
+ /**
+ * Toggle the addOpen state, whether to open "add collection" option
+ */
+ handleAddCollectionToggle = () => {
this.setState({ addOpen: !this.state.addOpen });
}
- handleOpenClassToggle = () => {
+ /**
+ * Toggle the openOpen state, whether to open "open collection" option
+ */
+ handleOpenCollectionToggle = () => {
this.setState({ openOpen: !this.state.openOpen });
}
- handleDeleteClassToggle = () => {
+ /**
+ * Toggle the deleteOpen state, whether to open "delete collection" option
+ */
+ handleDeleteCollectionToggle = () => {
this.setState({ deleteOpen: !this.state.deleteOpen });
}
+ /**
+ * Close the collection modal and all options
+ */
handleCloseAll = () => {
this.setState({ addOpen: false, openOpen: false, deleteOpen: false });
this.props.handleCollectionClose();
}
+ /**
+ * Returns DOM element for modal to select collections
+ */
selectCollection = () => {
const userCollections = this.props.collections.collections;
let optionItems = [];
@@ -139,6 +170,9 @@ class CollectionModal extends Component {
);
}
+ /**
+ * Returns DOM element for modal to delete collections
+ */
deleteCollection = () => {
const userCollections = this.props.collections.collections;
let optionItems = [];
@@ -159,10 +193,13 @@ class CollectionModal extends Component {
);
}
+ /**
+ * Add new collection to the backend if possible
+ */
handleSubmit = () => {
if (!this.props.user) {
window.alert("You must be signed in to create a collection.");
- this.handleAddClassToggle();
+ this.handleAddCollectionToggle();
}
else {
let name = this.state.newcollectionID.toLowerCase();
@@ -190,6 +227,9 @@ class CollectionModal extends Component {
}
}
+ /**
+ * Returns DOM element for modal to add collections
+ */
addClass = () => (
Please enter a new collection name.
@@ -231,13 +271,13 @@ class CollectionModal extends Component {
{ this.handleOpenClassToggle(); }} >
+ onClick={() => { this.handleOpenCollectionToggle(); }} >
storage
Open a Collection
{ this.handleDeleteClassToggle(); }} >
+ onClick={() => { this.handleDeleteCollectionToggle(); }} >
delete
Delete a Collection
@@ -245,7 +285,7 @@ class CollectionModal extends Component {
this.handleDeleteClassToggle()} >
+ onClick={() => this.handleDeleteCollectionToggle()} >
clear
diff --git a/src/components/collection/SelectProject.js b/src/components/collection/SelectProject.js
index eb641c87..e20d43c9 100644
--- a/src/components/collection/SelectProject.js
+++ b/src/components/collection/SelectProject.js
@@ -23,21 +23,23 @@ const selectStyle = {
...base,
zIndex: "999"
}),
-
};
+/**
+ * React component for selecting list of projects from collection
+ */
class SelectProject extends PureComponent {
+
+ /**
+ * Fetch the selected scene when the project is selected from the collection
+ * @param {Event} projectID ID of the project to be fetch
+ */
handleChange = (projectID) => {
// show warning if there's unsaved change
if(this.hasEditorChanged()){
- if((window.confirm("Are you sure you want to continue?\nYou will lose any unsaved work!"))){
- if (this.props.user && this.props.user.uid) {
- this.props.editorActions.fetchScene(projectID.value, this.props.uid);
- } else {
- this.props.editorActions.fetchScene(projectID.value);
- }
+ if(!window.confirm("Are you sure you want to continue?\nYou will lose any unsaved work!")){
+ return;
}
- return;
}
if (this.props.user && this.props.user.uid) {
@@ -47,6 +49,10 @@ class SelectProject extends PureComponent {
}
}
+ /**
+ * Returns wheter the text in the editor match with the savedText
+ * @returns {boolean} true if savedText is different from text in editor, false otherwise.
+ */
hasEditorChanged = () => {
let text;
try {
@@ -62,6 +68,9 @@ class SelectProject extends PureComponent {
return true;
}
+ /**
+ * @returns Returns DOM Elements of drop down list of projects
+ */
renderSelect = () => {
let collection = this.props.collection;
const placeholder = "Select a project";
@@ -78,6 +87,9 @@ class SelectProject extends PureComponent {
);
}
+ /**
+ * @returns Render DOM elements of drop down list of collection
+ */
render() {
return (
diff --git a/src/components/courses/Course.js b/src/components/courses/Course.js
index 4f3278d3..ebd9b29a 100644
--- a/src/components/courses/Course.js
+++ b/src/components/courses/Course.js
@@ -6,31 +6,38 @@ import {
Tooltip
} from "@material-ui/core";
+/**
+ * React component for navigating the course lessons and displaying lesson name and description
+ */
class Lesson extends Component {
+ /**
+ * Load next lesson. Give a warning if there's any changes in the editor
+ */
nextLesson = () => {
const currentIndex = this.props.courses.currentIndex;
const lessons = this.props.course.lessons;
- if(this.hasEditorChanged()){
- if (window.confirm("Are you sure you want to continue?\nYou will lose any unsaved work!")) {
- this.props.courseActions.nextLesson(currentIndex, lessons[currentIndex + 1]);
- }
- }else{
- this.props.courseActions.nextLesson(currentIndex, lessons[currentIndex + 1]);
+ if(this.hasEditorChanged() && !window.confirm("Are you sure you want to continue?\nYou will lose any unsaved work!")){
+ return;
}
+ this.props.courseActions.nextLesson(currentIndex, lessons[currentIndex + 1]);
}
+ /**
+ * Load previous lesson. Give a warning if there's any changes in the editor
+ */
lastLesson = () => {
const currentIndex = this.props.courses.currentIndex;
const lessons = this.props.course.lessons;
- if(this.hasEditorChanged()){
- if (window.confirm("Are you sure you want to continue?\nYou will lose any unsaved work!")) {
- this.props.courseActions.previousLesson(currentIndex, lessons[currentIndex - 1]);
- }
- }else{
- this.props.courseActions.previousLesson(currentIndex, lessons[currentIndex - 1]);
+ if(this.hasEditorChanged() && !window.confirm("Are you sure you want to continue?\nYou will lose any unsaved work!")){
+ return;
}
+ this.props.courseActions.previousLesson(currentIndex, lessons[currentIndex - 1]);
}
+ /**
+ * Returns wheter the text in the editor match with the savedText
+ * @returns {boolean} true if savedText is different from text in editor, false otherwise.
+ */
hasEditorChanged = () => {
let text;
try {
@@ -47,6 +54,9 @@ class Lesson extends Component {
return true;
}
+ /**
+ * @returns DOM Elements of button that go to previous or
+ */
renderBtns = () => {
const { course, courses } = this.props;
let nextValid = courses && courses.currentIndex !== null && course && course.lessons;
@@ -84,6 +94,9 @@ class Lesson extends Component {
);
}
+ /**
+ * @returns Render DOM elements of course lessons
+ */
render() {
return (
diff --git a/src/components/courses/CourseSelect.js b/src/components/courses/CourseSelect.js
index e969a27e..af1eb9e8 100644
--- a/src/components/courses/CourseSelect.js
+++ b/src/components/courses/CourseSelect.js
@@ -31,8 +31,8 @@ function getModalStyle() {
/**
* CSS for modal
- *
- * @param {*} theme !!!DESCRIPTION NEEDED!!!
+ *
+ * @param {*} theme Will use default theme if not provided
*/
const modelStyles = theme => ({
paper: {
@@ -48,14 +48,15 @@ const modelStyles = theme => ({
}
});
+/**
+ * React component for creating modal listing courses
+ */
class CourseSelectModal extends Component {
- constructor(props) {
- super(props);
- this.state = {
- // open: false
- };
- }
-
+ /**
+ * Helper function to create card for a course modal.
+ * @param {object} course Object with course info
+ * @returns {HTMLElement} Card element of course
+ */
helper = (course) => {
if (course) {
let id = course._id;
@@ -89,6 +90,7 @@ class CourseSelectModal extends Component {
/**
* Render all of the elements
+ * @returns {HTMLElement} Course modal with the list of course cards
*/
render() {
const { classes } = this.props;
diff --git a/src/components/editor/Editor.js b/src/components/editor/Editor.js
index 62ef4a15..d6041d05 100644
--- a/src/components/editor/Editor.js
+++ b/src/components/editor/Editor.js
@@ -10,9 +10,15 @@ import KeyboardShortcut from "./KeyboardShortcut.js";
import { browserType } from "../../utils/browserType";
/**
- * Editor is a React Component that creat the Ace Editor in the DOM.
+ * Editor is a React Component that create the Ace Editor in the DOM.
*/
class Editor extends Component {
+ /**
+ * Called when the Edtior is unmounting (Being removed from the DOM)
+ *
+ * Editor will unmount when MYR enters ViewOnly mode, and we want to render
+ * whatever the code that's in the editor.
+ */
componentWillUnmount() {
// Updates state in reducer before closing editor
const text = window.ace.edit("ace-editor").getSession().getValue();
@@ -22,6 +28,12 @@ class Editor extends Component {
this.props.render(text);
}
+ /**
+ * Called when the Editor is mounted (component has been rendererd to the DOM)
+ *
+ * It sets custom completer of MYR API to editor,
+ * and add listener to check whether user have unsaved changes.
+ */
componentDidMount() {
try {
// eslint-disable-next-line
@@ -47,6 +59,10 @@ class Editor extends Component {
});
}
+ /**
+ * Called when the editor is loaded.
+ * It sets options to set the maximum error editor accepts and set the EMCAScript version to 6
+ */
onLoad() {
window.ace.edit("ace-editor").session.$worker.send("setOptions", [{
"maxerr": 1000,
diff --git a/src/components/editor/KeyboardShortcut.js b/src/components/editor/KeyboardShortcut.js
index cea5bccf..53c367cb 100644
--- a/src/components/editor/KeyboardShortcut.js
+++ b/src/components/editor/KeyboardShortcut.js
@@ -69,6 +69,9 @@ const scene = [
},
];
+/**
+ * React components create the button with KeyboardShortcut window
+ */
class KeyboardShortcut extends React.Component {
constructor(props){
super(props);
@@ -78,6 +81,11 @@ class KeyboardShortcut extends React.Component {
};
}
+ /**
+ * Helper function to convert the shrotcuts to an equivalent DOM elements
+ *
+ * @param {array} data
+ */
shortcutHelper = (data) => {
let shortcuts = [];
data.shortcut.forEach((key,i)=>{
@@ -89,18 +97,31 @@ class KeyboardShortcut extends React.Component {
return (
{shortcuts} {data.description}
);
};
+ /**
+ * Update the state when the button is clicked
+ *
+ * @param {object} event target to anchor the window
+ */
handleClick = (event) =>{
this.setState({
open: true,
anchorEl: event.target});
};
+ /**
+ * Update the state when the window is closed
+ *
+ * @param {object} event target to anchor the window
+ */
handleClose = () => {
this.setState({
open: false,
anchorEl: null});
};
+ /**
+ * Creates the keyboard shortcut in the DOM
+ */
render(){
return(
diff --git a/src/components/editor/customCompleter.js b/src/components/editor/customCompleter.js
index 91e6b1d2..b30fecb0 100644
--- a/src/components/editor/customCompleter.js
+++ b/src/components/editor/customCompleter.js
@@ -2,9 +2,12 @@ import myrReference from "../../myr/reference.js";
import myrTextures from "../structural/Textures.js";
import myrModels from "../structural/Models.js";
+/**
+ * Creates customCompleter for all MYR references and keywords for JS, color code, and assets
+ */
export const customCompleter = {
getCompletions: function (editor, session, pos, prefix, callback) {
- let BasicAutocompleteKeyWords = [
+ const BasicAutocompleteKeyWords = [
"const",
"yield",
"import",
@@ -36,25 +39,21 @@ export const customCompleter = {
"static"
];
- let texture = myrTextures();
- let Texture = [...texture.TexturePack.map(obj => obj.title),
- "group()"
- ];
+ const texture = myrTextures();
+ const Texture = [...texture.TexturePack.map(obj => obj.title)];
- let model = myrModels();
- let Model = [...model.ModelPack.keys(),
- "group()"
- ];
+ const model = myrModels();
+ const Model = [...model.ModelPack.keys()];
- let reference = myrReference();
- let keyWords = [...reference.geometry.map(obj => obj.name + "()"),
+ const reference = myrReference();
+ const MYRKeyWords = [...reference.geometry.map(obj => obj.name + "()"),
...reference.transformations.map(obj => obj.name + "()"),
...reference.animations.map(obj => obj.name + "()"),
...reference.lights.map(obj=>obj.name+"()"),
"group()"
];
- let Colors = [
+ const Colors = [
"aliceblue",
"antiquewhite",
"aqua",
@@ -214,7 +213,7 @@ export const customCompleter = {
};
}));
- callback(null, keyWords.map(function (word) {
+ callback(null, MYRKeyWords.map(function (word) {
return {
caption: word,
value: word,
diff --git a/src/components/layouts/AssetReference.js b/src/components/layouts/AssetReference.js
index daa42a69..d4bcfd89 100644
--- a/src/components/layouts/AssetReference.js
+++ b/src/components/layouts/AssetReference.js
@@ -5,6 +5,11 @@ import AssetReferencePage from "../reference/AssetReferencePage";
import * as layoutTypes from "../../constants/LayoutTypes.js";
+/**
+ * Create a layout for model reference page.
+ * @param {object} param0 List of props that will be use in components
+ * @returns {HTMLElement} Layout of the model reference page
+ */
export const AssetReference = ({ editor, editorActions, user, authActions, scene, sceneActions, projectActions, courseActions, projects, courses, match, collectionActions, collections }) => (
(
diff --git a/src/components/layouts/Guided.js b/src/components/layouts/Guided.js
index d6bbcee3..aa23176f 100644
--- a/src/components/layouts/Guided.js
+++ b/src/components/layouts/Guided.js
@@ -7,6 +7,11 @@ import View from "../structural/View";
import * as layoutTypes from "../../constants/LayoutTypes.js";
+/**
+ * Create a layout for course page.
+ * @param {object} param0 List of props that will be use in components
+ * @returns {HTMLElement} Layout of the course page
+ */
export const Guided = ({ editor, user, scene, editorActions, authActions, projectActions, projects, courseActions, courses, course, match, sceneActions, collectionActions, collections }) => (
(
(
(
+
diff --git a/src/components/reference/ModelReferenceTab.js b/src/components/reference/ModelReferenceTab.js
index c82ef5ec..218bef04 100644
--- a/src/components/reference/ModelReferenceTab.js
+++ b/src/components/reference/ModelReferenceTab.js
@@ -11,7 +11,7 @@ import {
TableCell
} from "@material-ui/core";
-import "../../css/ModelReferencePage.css";
+import "../../css/ReferencePage.css";
export default class ModelReference extends React.Component {
imageHelper = (model) => {
diff --git a/src/components/reference/RefExInfo.js b/src/components/reference/RefExInfo.js
index d43511b9..958ae2fb 100644
--- a/src/components/reference/RefExInfo.js
+++ b/src/components/reference/RefExInfo.js
@@ -4,8 +4,16 @@ import {
Icon
} from "@material-ui/core";
+/**
+ * Reference Example Box is react component for displaying information about
+ * API in reference example scene
+ */
class ReferenceExampleBox extends Component {
-
+ /**
+ * Check the redux state to see if example has suggested course
+ * and create elements according to it
+ * @returns {Button} Button with name of suggested course on it
+ */
suggestedCourse = () => {
const { suggestedCourse, suggestedCourseName } = this.props.referenceExample;
return (
@@ -24,6 +32,12 @@ class ReferenceExampleBox extends Component {
);
}
+ /**
+ * Returns parentheses that includes parameters for the example
+ *
+ * @param {array} functionParams array of paremeter names
+ * @returns {string} list of
+ */
renderParams = (functionParams) => {
let returnString = "(";
for (let i = 0; i < functionParams.length; i++) {
@@ -34,6 +48,10 @@ class ReferenceExampleBox extends Component {
// return returnString;
}
+ /**
+ * Create header element with function name and parameters
+ * @returns {HTMLElement} h3 tag with "Function: name(parameters)"
+ */
renderTitle = () => {
const { functionName, functionParams } = this.props.referenceExample;
return (
@@ -44,6 +62,9 @@ class ReferenceExampleBox extends Component {
);
}
+ /**
+ * Render title and description of example scene
+ */
render() {
return (
@@ -56,5 +77,4 @@ class ReferenceExampleBox extends Component {
}
}
-
export default ReferenceExampleBox;
diff --git a/src/components/reference/Reference.js b/src/components/reference/Reference.js
index c269e148..c4e44723 100644
--- a/src/components/reference/Reference.js
+++ b/src/components/reference/Reference.js
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { Component } from "react";
import myrReference from "../../myr/reference";
import * as refFunctions from "../../myr/reference";
@@ -36,8 +36,15 @@ const assetReferenceBtn = {
top: 0,
right: 95,
};
-export default class Reference extends React.Component {
+/**
+ * Reference is a react component that creates drawer contains references
+ */
+class Reference extends Component {
+ /**
+ * Constructor
+ * value represents the current tab that's opened
+ */
constructor(props) {
super(props);
this.state = {
@@ -46,10 +53,19 @@ export default class Reference extends React.Component {
this.tableData = myrReference();
}
+ /**
+ * Handler for when user clicked the tab, it updates the state "value" with value passed in
+ *
+ * @param {Event} event
+ * @param {string} value tab to be changed to. It should be an alphabet
+ */
handleChange = (event, value) => {
this.setState({ value });
};
+ /**
+ * Handler for opening the reference page
+ */
handleOpen = () => {
window.open(window.origin + "/reference");
this.setState({ value: "a" });
@@ -83,6 +99,11 @@ export default class Reference extends React.Component {
);
};
+ /**
+ * Create a button that will link to the example scene
+ * @param {string} example name of the API
+ * @returns {HTMLElement} IconButton with link to the example scene
+ */
exampleHelper = (example) => {
if (example) {
let link = "/reference/" + example;
@@ -99,8 +120,13 @@ export default class Reference extends React.Component {
}
};
+ /**
+ * Create a table of references by retrieve array of references from tableData by category
+ *
+ * @param {string} category name of the category
+ * @returns {Table} DOM elements of table with references with passed category
+ */
TableEx = (category) => {
-
return (
@@ -123,6 +149,9 @@ export default class Reference extends React.Component {
);
};
+ /**
+ * Reneter Button that will open Drawer of reference with different categories
+ */
render() {
const style = {
margin: 2,
@@ -177,7 +206,6 @@ export default class Reference extends React.Component {
settings_system_daydream
-
- );
- };
-
+/**
+ * ReferencePage extends Reference class and overrides the render function to create as single page
+ */
+class ReferencePage extends Reference {
+ /**
+ * Render reference page
+ */
render() {
document.title = "Reference | MYR";
return (
@@ -176,3 +99,5 @@ export default class Reference extends React.Component {
);
}
}
+
+export default ReferencePage;
\ No newline at end of file
diff --git a/src/components/reference/TextureReferenceTab.js b/src/components/reference/TextureReferenceTab.js
index d399a1ad..0d64f131 100644
--- a/src/components/reference/TextureReferenceTab.js
+++ b/src/components/reference/TextureReferenceTab.js
@@ -11,7 +11,7 @@ import {
TableCell,
} from "@material-ui/core";
-import "../../css/TextureReferencePage.css";
+import "../../css/ReferencePage.css";
export default class TextureReference extends React.Component {
imageHelper = (image) => {
diff --git a/src/components/structural/Footer.js b/src/components/structural/Footer.js
index 876b75dd..e6eaeee3 100644
--- a/src/components/structural/Footer.js
+++ b/src/components/structural/Footer.js
@@ -1,5 +1,8 @@
import React, { Component } from "react";
+/**
+ * React component class for the footer includes link to about page, privacy policy, TOS, etc.
+ */
class Footer extends Component {
render() {
return (
diff --git a/src/components/structural/Models.js b/src/components/structural/Models.js
index ec66a713..86b2a0c4 100644
--- a/src/components/structural/Models.js
+++ b/src/components/structural/Models.js
@@ -1,3 +1,6 @@
+/**
+ * Map of textures' name and url and img url for retrieval
+ */
let ModelPack = new Map();
// Models that have been cleared for us to host
ModelPack.set("sword", {model: "/models/sword.glb", image: "/img/models/sword.png"});
diff --git a/src/components/structural/Textures.js b/src/components/structural/Textures.js
index be39c962..6e43dc44 100644
--- a/src/components/structural/Textures.js
+++ b/src/components/structural/Textures.js
@@ -1,4 +1,7 @@
-let TexturePack = [
+/**
+ * List of textures' name and url for retrieval
+ */
+const TexturePack = [
{title:"bricks",url:"/img/textures/bricks.jpg"},
{title:"bark",url:"/img/textures/bark.jpg"},
{title:"checkerboard",url:"/img/textures/checkerboard.jpg"},
diff --git a/src/components/structural/View.js b/src/components/structural/View.js
index 8445b602..791c1819 100644
--- a/src/components/structural/View.js
+++ b/src/components/structural/View.js
@@ -18,10 +18,21 @@ class View extends Component {
welcomeOpen: true
};
}
+ /**
+ * The timer ID set to check if the welcome screen is open
+ * It will use it to cancel the timer once the welcome screen is close
+ */
intervalID = 0;
- componentDidMount() {
- // Don't show editor if welcome screen is open
+ /**
+ * Called when the MYR Scene is mounted (component has been rendererd to the DOM)
+ *
+ * It check if the user's first time visiting, then it will set up a interval to see if the welcome screen is closed for every 1000ms
+ * It also add a event listener to
+ * stop key press of movement (arrow key and space) to scroll the page
+ * hide or show "interface" (editor) depends on when user enter or exit the VR(fullscreen) mode.
+ */
+ componentDidMount() {
if (!this.getCookie("hasVisited")) {
this.intervalID = setInterval(this.checkForWelcomeScreen, 1000);
}
@@ -45,7 +56,10 @@ class View extends Component {
}
/**
- * This fires off an event when the system is fully rendered.
+ * Called when MYR Scene is rendererd (DOM elements is changed/updated)
+ *
+ * If the welcome screen is closed, it fires an event for "myr-view-rendererd" which added in
+ * change() & push() in Myr.js but these are unused functions that are not documented in reference.
*/
componentDidUpdate() {
if (!this.state.welcomeOpen) {
@@ -54,14 +68,24 @@ class View extends Component {
// Dispatch/Trigger/Fire the event
document.dispatchEvent(event);
- }
-
+ }
}
+ /**
+ * Called when the MYR Scene is unmounting (Being removed from the DOM)
+ *
+ * It will check if the timerID for checking welcome screen is set,
+ * If so it will clear/stop the timer from checking.
+ */
componentWillUnmount() {
if (this.intervalID !== 0) { clearInterval(this.intervalID); }
}
+ /**
+ * On every interval (1000ms) it check whether the cookie hasVisited is set to true
+ * If so, set state "welcomeOpen" to false (so it will render the scene)
+ * and stop the timer.
+ */
checkForWelcomeScreen = () => {
if (this.getCookie("hasVisited")) {
this.setState({ welcomeOpen: false });
@@ -70,6 +94,11 @@ class View extends Component {
}
}
+ /**
+ * Get value of cookie
+ * @param {string} cookieName name of cookie
+ * @returns {string} value of cookie if it exist, return empty string otherwise
+ */
getCookie = (cookieName) => {
let name = cookieName + "=";
let decodedCookie = decodeURIComponent(document.cookie);
@@ -87,9 +116,10 @@ class View extends Component {
}
/**
- * This renders json to aframe entities
+ * A helper function that converts MYR objects into a corresponded A-Frame DOM elements
*
- * @param {*} ent
+ * @param {object} ent MYR object
+ * @returns {HTMLElement} A-Frame entities
*/
helper = (ent) => {
if (ent) {
@@ -142,9 +172,13 @@ class View extends Component {
return ;
}
}
- //return elements that contains necessary configuration for light indicator based on light's type and properties
+ /**
+ * Helper fuctions that returns A-Frame elements that contains necessary configuration for light indicator based on light's type and properties
+ *
+ * @param {object} ent Myr object
+ * @returns A-Frame entities of light indicator
+ */
lightIndicatorHelper =(ent)=>{
-
//this is a position for passing in to indicatorroation to determine the rotation of the light that use position as vector.
let position =`position:${ent.position.x || 0} ${ent.position.y || 0} ${ent.position.z || 0};`;
if(ent.light.target){
@@ -169,7 +203,13 @@ class View extends Component {
default:
}
}
- //return string that contains necessary configuration for shadow based on light's type
+
+ /**
+ * Helper function that returns configuration for shadow based on light's type
+ *
+ * @param {object} light light properties
+ * @returns {string} string of aframe configuration of shadow that will attach to the light attribute
+ */
lightShadowHelper = (light) =>{
let newState = "";
//ambient and hemisphere light doesn't cast shadow
@@ -188,12 +228,23 @@ class View extends Component {
return newState;
}
+ /**
+ * Help convert asset(model,image,etc) datas to A-Frame entitiy
+ *
+ * @param {object} asset
+ * @returns {HTMLElement} a-asset-item of the object
+ */
assetsHelper = (asset) => {
return (
);
}
+ /**
+ * It creates 2 different A-Frame camera. As for now, it will always be basicMoveCam.
+ *
+ * @returns {HTMLElement} Camera elements
+ */
createCam = () => {
switch (this.props.sceneConfig.settings.camConfig) {
case 0:
@@ -205,6 +256,14 @@ class View extends Component {
}
}
+ /**
+ * Check point cam is a mode where there's a checkpoints in the scene where user can select them to teleport to that position
+ * to move around the scene compare to the regular movement.
+ *
+ * Check point is currently not implemented in MYR to be an usable feature.
+ *
+ * @returns {HTMLElement} Camera elements contains checkpoint control
+ */
checkpointCam = () => {
return (
@@ -220,6 +279,18 @@ class View extends Component {
);
}
+
+ /**
+ * It returns camera basic with different movement control depends on the browser type
+ * Mobile:
+ * default movement controls with flying enabled
+ * VR:
+ * default movement controls with flying disabled
+ * Desktop:
+ * custom wasd-plus-control with controllable movement speed
+ *
+ * @returns {HTMLElement} A-Frame camera elements with basic movement
+ */
basicMoveCam = () => {
switch(browserType()) {
case "mobile":
@@ -276,15 +347,17 @@ class View extends Component {
/**
* Produces the grid on the ground and the coordinate lines
+ *
+ * @returns {HTMLElements} A-Frame entitiy containing grid, tube for axies and text to label those axes
*/
coordinateHelper = () => {
if (this.props.sceneConfig.settings.showCoordHelper) {
return (
-
-
-
-
+
+
+
+ {
if (this.props.sceneConfig.settings.showFloor) {
return (
@@ -331,6 +408,11 @@ class View extends Component {
}
}
+ /**
+ * Main part for Rendering MYR Scene!
+ *
+ * @returns {HTMLElement} A-Frame scene containing all the settings and MYR objects
+ */
render = () => {
/* eslint-disable */
return (
diff --git a/src/components/structural/WelcomeScene.js b/src/components/structural/WelcomeScene.js
index 5b76ad15..2a8072be 100644
--- a/src/components/structural/WelcomeScene.js
+++ b/src/components/structural/WelcomeScene.js
@@ -1,7 +1,14 @@
import React, { Component } from "react";
import { browserType } from "../../utils/browserType";
+/**
+ * Welcome Scene component returns static aframe scene to embed in welcome screen
+ */
class WelcomeScene extends Component {
+ /**
+ * Create basicMoveCam
+ * Refer to basicMoveCam in View.js for more detail description
+ */
createCam = () => {
switch(browserType()) {
case "mobile":
@@ -52,6 +59,9 @@ class WelcomeScene extends Component {
}
}
+ /**
+ * @returns aframe scene that same as dropsies scene from example project
+ */
render() {
return (
diff --git a/src/components/structural/WelcomeScreen.js b/src/components/structural/WelcomeScreen.js
index f61bab08..1dca3fad 100644
--- a/src/components/structural/WelcomeScreen.js
+++ b/src/components/structural/WelcomeScreen.js
@@ -15,6 +15,9 @@ import CourseSelect from "../courses/CourseSelect.js";
import { withStyles } from "@material-ui/core/styles";
import "../../css/WelcomeScreen.css";
+/**
+ * @returns {object} Center the Welcome Screen
+ */
function getOuterModalStyle() {
const top = 50;
const left = 50;
@@ -65,6 +68,10 @@ const exitBtnStyle = {
top: 0,
right: 0,
};
+
+/**
+ * Welcome Component returns a modal of welcome screen that shows up when user first enter MYR
+ */
class Welcome extends React.Component {
constructor(props) {
super(props);
@@ -75,12 +82,23 @@ class Welcome extends React.Component {
};
}
+ /**
+ * Called when the Welcome Screen is mounted (component has been rendererd to the DOM)
+ *
+ * Header.js has a state to control whether to show welcome screen or not. By default it's false.
+ * So if user hasn't visisted the MYR, toggle the state to true.
+ */
componentDidMount() {
if (!this.getCookie("hasVisited")) {
this.props.handleWelcomeToggle();
}
}
+ /**
+ * Get value of cookie
+ * @param {string} cookieName name of cookie
+ * @returns {string} value of cookie if it exist, return empty string otherwise
+ */
getCookie = (cookieName) => {
let name = cookieName + "=";
let decodedCookie = decodeURIComponent(document.cookie);
@@ -97,6 +115,11 @@ class Welcome extends React.Component {
return "";
}
+ /**
+ * If the user is first visiting the MYR, set "hasVisisted" to true
+ * and set the expiration date to current date + 24 hrs
+ * So it will re-appear after 24 hrs
+ */
setCookie = () => {
if (!this.getCookie("hasVisited")) {
let date = new Date();
@@ -107,16 +130,26 @@ class Welcome extends React.Component {
}
}
+ /**
+ * Handler for when the welcome screen is close either by close button or clicking outside of modal
+ */
handleClose = () => {
this.setCookie();
this.props.handleWelcomeToggle();
};
+ /**
+ * Handler for when user click "never again" button
+ * It sets a long expiration date so it will "never" expireds
+ */
neverAgainCookie = () => {
document.cookie = "hasVisited=true; expires=Thu, 31 Dec 2099 12:00:00 UTC;";
this.handleClose();
}
+ /**
+ * @returns {*} Button with don't show again option
+ */
neverAgain = () => {
return (