Compare commits

...

6 Commits

Author SHA1 Message Date
03ed1f22e8 qr code added 2024-08-20 00:18:20 -04:00
b0c6bf37b8 possible fix for arm? :P 2024-08-19 12:43:14 -04:00
52199477d5 possible fix for arm? :P 2024-08-19 12:38:10 -04:00
2798c9d759 Settings page revamp 2024-08-16 21:45:46 -04:00
d27071dbd3 Co-authored-by: Lucas Ferguson <LucasFerguson@users.noreply.github.com>
Co-authored-by: Dustin Thomas <stdio@cptlobster.dev>
2024-08-16 20:01:38 -04:00
9dcebb9d88 Arm in motion modal 2024-08-16 18:21:34 -04:00
27 changed files with 656 additions and 291 deletions

View File

@ -5,39 +5,27 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Belden Jukebox</title> <title>Belden Jukebox</title>
</head> </head>
<body> <body>
<noscript>Belden Jukebox UI</noscript> <noscript>
<p>
<b>Belden Jukebox Error:</b><br />
JavaScript is required to run this application.<br />
Please enable JavaScript in your browser.<br /><br />
<a
href="https://www.enable-javascript.com/"
target="_blank"
rel="noopener noreferrer"
>
Here are the instructions how to enable JavaScript in your web
browser!
</a>
</p>
</noscript>
<div id="root"></div> <div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body> </body>
</html> </html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -62,7 +62,7 @@ $white: #fff;
); );
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: space-between;
flex-direction: row; flex-direction: row;
border-radius: 20px; border-radius: 20px;
border: 1px solid $gray; border: 1px solid $gray;
@ -134,7 +134,8 @@ $white: #fff;
background-color: transparent; background-color: transparent;
} }
.cable-main-image { .cable-main-image,
.cable-main-imageqr {
aspect-ratio: 1/1; aspect-ratio: 1/1;
width: auto; width: auto;
height: 100%; height: 100%;
@ -146,6 +147,23 @@ $white: #fff;
filter: drop-shadow(0 4px 4px rgb(0 0 0 / 25%)); filter: drop-shadow(0 4px 4px rgb(0 0 0 / 25%));
} }
.cable-main-imageqr {
margin-right: 0;
margin-left: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.cable-main-imageqr img {
width: 80%;
height: 80%;
object-fit: cover;
background-color: white;
border: $gray solid 1px;
filter: drop-shadow(0 4px 4px rgb(0 0 0 / 25%));
}
.cable-main-label { .cable-main-label {
width: 60%; width: 60%;
height: 100%; height: 100%;

View File

@ -33,6 +33,7 @@ $white: #fff;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
flex-direction: row; flex-direction: row;
padding-top: 20px;
} }
.navbar-top-secret { .navbar-top-secret {
@ -51,10 +52,9 @@ $white: #fff;
justify-content: left; justify-content: left;
padding-left: 4px; padding-left: 4px;
text-align: center; text-align: center;
margin-top: 20px; color: $medium-blue;
margin-bottom: 15px;
color: $light-blue;
background-color: transparent; background-color: transparent;
margin-left: 2px;
} }
.navbar-top h1 { .navbar-top h1 {
@ -80,7 +80,8 @@ $white: #fff;
} }
.navbar-list-item, .navbar-list-item,
.navbar-return { .navbar-return,
.navbar-settings {
width: 100%; width: 100%;
height: 50px; height: 50px;
margin: 0 0 3px; margin: 0 0 3px;
@ -95,7 +96,8 @@ $white: #fff;
} }
.navbar-list-item span, .navbar-list-item span,
.navbar-return span { .navbar-return span,
.navbar-settings span {
background-color: transparent; background-color: transparent;
width: auto; width: auto;
height: auto; height: auto;
@ -105,6 +107,19 @@ $white: #fff;
margin-left: 10px; margin-left: 10px;
} }
.navbar-settings {
width: 40px;
height: 40px;
justify-content: center;
align-items: center;
margin: 0;
background-color: $medium-blue;
}
.navbar-settings span {
margin: 0;
}
.navbar-return { .navbar-return {
width: 90%; width: 90%;
align-items: center; align-items: center;
@ -131,6 +146,7 @@ $white: #fff;
.modal-title, .modal-title,
.modal-body, .modal-body,
.modal-close, .modal-close,
.modal-closeX,
.modal-return { .modal-return {
width: auto; width: auto;
height: auto; height: auto;
@ -175,7 +191,8 @@ $white: #fff;
} }
.modal-close, .modal-close,
.modal-return { .modal-return,
.modal-closeX {
cursor: pointer; cursor: pointer;
padding: 15px 35px; padding: 15px 35px;
border-radius: 20px; border-radius: 20px;
@ -186,7 +203,8 @@ $white: #fff;
} }
.modal-close span, .modal-close span,
.modal-return span { .modal-return span,
.modal-closeX span {
width: auto; width: auto;
height: auto; height: auto;
background-color: transparent; background-color: transparent;
@ -196,9 +214,14 @@ $white: #fff;
color: $dark-blue; color: $dark-blue;
} }
.modal-closeX {
background-color: rgb(255, 152, 152);
box-shadow: 0 4px 4px rgba(94, 1, 1, 0.25);
}
.modal-return { .modal-return {
width: 30px; width: auto;
height: 20px; height: auto;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-left: 10px; margin-left: 10px;

View File

@ -66,19 +66,19 @@ $white: #fff;
text-align: left; text-align: left;
} }
.settings-powerContainer, .settings-grid,
.settings-creditsContainer { .settings-creditsContainer {
width: 80%; width: 80%;
height: 100px; height: auto;
background: linear-gradient( background: linear-gradient(
-30deg, -30deg,
rgb(187 208 236) 0%, rgb(187 208 236) 0%,
rgb(255 255 255 / 100%) 100% rgb(255 255 255 / 100%) 100%
); );
display: flex; display: flex;
align-items: center; align-items: flex-start;
justify-content: flex-start; justify-content: center;
flex-direction: row; flex-direction: column;
border-radius: 20px; border-radius: 20px;
border: 1px solid $gray; border: 1px solid $gray;
margin-bottom: 5px; margin-bottom: 5px;
@ -89,6 +89,29 @@ $white: #fff;
filter: drop-shadow(0 4px 4px rgb(0 0 0 / 25%)); filter: drop-shadow(0 4px 4px rgb(0 0 0 / 25%));
} }
.settings-gridInner {
width: 100%;
height: auto;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
padding: 15px 0px 15px 0px;
background-color: transparent;
}
.settings-grid h2 {
width: 100%;
height: auto;
font-size: 24px;
font-weight: bold;
color: $dark-blue;
font-family: "Gotham Medium";
text-align: left;
padding: 20px 10px 0px 10px;
background-color: transparent;
}
.settings-creditsContainer { .settings-creditsContainer {
height: 500px; height: 500px;
display: flex; display: flex;
@ -96,10 +119,10 @@ $white: #fff;
align-items: center; align-items: center;
} }
.settings-powerButton { .settings-button {
width: 200px; width: auto;
height: 50px; height: 40px;
border-radius: 20px; border-radius: 15px;
background: linear-gradient( background: linear-gradient(
15deg, 15deg,
rgb(223 223 223) 0%, rgb(223 223 223) 0%,
@ -112,78 +135,182 @@ $white: #fff;
filter: drop-shadow(5px 5px 2px rgb(0 0 0 / 15%)); filter: drop-shadow(5px 5px 2px rgb(0 0 0 / 15%));
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
margin-right: 20px; margin-right: 10px;
margin-left: 20px; margin-left: 10px;
} }
.settings-powerButton span { .settings-button span {
width: auto; width: auto;
height: auto; height: auto;
font-size: 20px; font-size: 16px;
margin-top: 2px;
color: $medium-blue; color: $medium-blue;
font-family: "Gotham Bold"; font-family: "Gotham Bold";
background-color: transparent; background-color: transparent;
padding: 10px;
} }
.settings-credits { .settings-form {
width: 95%; width: 100%;
height: 430px; height: auto;
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
background-color: transparent; background-color: transparent;
}
// text box
#sendobject {
width: 90%;
height: 20px;
border-radius: 15px;
background-color: $white;
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: flex-start; align-items: flex-start;
flex-direction: column; transition: all 0.3s ease-in-out;
filter: drop-shadow(5px 5px 2px rgb(0 0 0 / 15%));
text-decoration: none;
margin-right: 10px;
margin-left: 10px;
padding: 10px;
margin-top: 10px;
margin-bottom: 10px;
border: 1px solid rgb(199, 199, 199);
text-align: left;
} }
.entry-links, #sendobject:focus {
.entry-name, outline: none;
.entry-position, }
.settings-credits-title {
#sendobjectButton {
width: 10%;
height: 40px;
border-radius: 15px;
background: linear-gradient(
15deg,
rgb(223 223 223) 0%,
rgb(255 255 255) 100%
);
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s ease-in-out;
filter: drop-shadow(5px 5px 2px rgb(0 0 0 / 15%));
cursor: pointer;
text-decoration: none;
margin-right: 10px;
margin-left: 10px;
margin-top: 10px;
margin-bottom: 10px;
}
#creditsgrid {
width: 100%;
height: auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
//background-color: red;
}
.entry {
width: 48%;
height: 150px;
border-radius: 15px;
background: linear-gradient(
15deg,
rgb(223 223 223) 0%,
rgb(255 255 255) 100%
);
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s ease-in-out;
filter: drop-shadow(5px 5px 2px rgb(0 0 0 / 15%));
text-decoration: none;
margin: 10px 10px 10px 10px;
}
.entry-image {
width: auto; width: auto;
height: auto; height: auto;
text-align: left; display: flex;
font-family: "Gotham Medium";
color: $light-blue;
font-size: 20px;
background-color: transparent; background-color: transparent;
background: transparent;
text-decoration: none;
margin-bottom: 7px;
margin-right: 30px;
} }
.settings-credits-title { .entry-img,
.entry-qr {
width: 110px;
height: 110px;
background: linear-gradient(
15deg,
rgb(223 223 223) 0%,
rgb(255 255 255) 100%
);
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
margin: 10px;
filter: drop-shadow(5px 5px 2px rgb(0 0 0 / 15%));
border: 1px solid $gray;
}
.entry-qr {
margin: 0px;
padding: 8px;
width: 40px;
height: 40px;
border-radius: 50px;
background: white;
position: fixed;
bottom: 5px;
margin-left: 90px;
}
.entry-qr img {
border-radius: 0px;
width: auto;
height: auto;
background: red;
}
.entry-title {
width: 70%;
height: 50%;
margin-left: 30px;
display: flex;
align-items: flex-start;
justify-content: center;
flex-direction: column;
background-color: transparent;
}
.entry-title h2,
.entry-title h3 {
width: auto;
height: auto;
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
color: $dark-blue; color: $dark-blue;
font-family: "Gotham Medium"; font-family: "Gotham Medium";
margin-bottom: 10px; text-align: left;
}
.entry {
width: 100%;
height: auto;
display: flex;
justify-content: flex-start;
align-items: center;
background-color: transparent; background-color: transparent;
text-align: start;
margin: 0px;
padding: 0px;
} }
.entry-name { .entry-title h2 {
width: auto; margin-bottom: 5px;
height: auto;
color: $medium-blue;
} }
.entry-position { .entry-title h3 {
width: auto; font-size: 16px;
height: auto; font-weight: normal;
color: $light-blue; color: $light-blue;
} }
.entry-links {
width: auto;
height: auto;
color: $hover-blue;
}

View File

@ -21,14 +21,11 @@ export default class BrowseComponent extends Component {
} }
handleMessage = (event) => { handleMessage = (event) => {
//console.log("Got message!");
try { try {
const message = JSON.parse(event.data); const message = JSON.parse(event.data);
const cableList = this.browseParse(message); const cableList = this.browseParse(message);
this.setState({ cableList }); this.setState({ cableList });
} catch (error) { } catch (error) {}
console.error("Error parsing message from server:", error);
}
}; };
browseParse(message) { browseParse(message) {

View File

@ -1,6 +1,7 @@
import React, { Component } from "react"; import React, { Component } from "react";
import BeldenLogo from "../assets/images/belden-white.png"; import BeldenLogo from "../assets/images/belden-white.png";
import DefaultPartImg from "../assets/images/part.png"; import DefaultPartImg from "../assets/images/part.png";
import DefaultQRImg from "../assets/images/default_qr.png";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import Modal from "react-modal"; import Modal from "react-modal";
import "../assets/stylesheets/cabledetail.scss"; import "../assets/stylesheets/cabledetail.scss";
@ -17,7 +18,7 @@ class Cable {
this.image = cableData.image this.image = cableData.image
? `http://${hostname}${cableData.image}` ? `http://${hostname}${cableData.image}`
: DefaultPartImg; : DefaultPartImg;
this.datasheet = `http://${hostname}${cableData.datasheet}` this.datasheet = `http://${hostname}${cableData.datasheet}`;
this.dynamicProps = {}; this.dynamicProps = {};
this.horizontal = []; this.horizontal = [];
this.vertical = []; this.vertical = [];
@ -26,6 +27,9 @@ class Cable {
this.short_description = cableData.short_description; this.short_description = cableData.short_description;
this.application = cableData.application; this.application = cableData.application;
this.category = cableData.category; this.category = cableData.category;
this.qrcode = cableData.qrcode
? `http://${hostname}${cableData.qrcode}`
: DefaultQRImg;
if (this.description === undefined) { if (this.description === undefined) {
if (this.short_description !== undefined) { if (this.short_description !== undefined) {
@ -60,6 +64,7 @@ class Cable {
"application", "application",
"category", "category",
"datasheet", "datasheet",
"qrcode",
].includes(key) ].includes(key)
) { ) {
this.dynamicProps[key] = cableData[key]; this.dynamicProps[key] = cableData[key];
@ -106,7 +111,6 @@ export default class CableDetailComponent extends Component {
super(props); super(props);
this.state = { this.state = {
cableDetails: null, cableDetails: null,
modalOpen_dispense: false,
modalOpen_show: false, modalOpen_show: false,
modalOpen_datasheet: false, modalOpen_datasheet: false,
modalOpacity: 0, modalOpacity: 0,
@ -120,11 +124,7 @@ export default class CableDetailComponent extends Component {
setTimeout(() => this.setState({ modalOpacity: 1 }), 10); setTimeout(() => this.setState({ modalOpacity: 1 }), 10);
}); });
if (modal === "modalOpen_dispense") { if (modal === "modalOpen_show") {
this.props.socket.send(
`{"type": "cable_get","call": "send","data": {"position": ${this.state.cableDetails.position}}}`
);
} else if (modal === "modalOpen_show") {
this.props.socket.send( this.props.socket.send(
`{"type": "cable_get","call": "request","data": {"position": ${this.state.cableDetails.position}}}` `{"type": "cable_get","call": "request","data": {"position": ${this.state.cableDetails.position}}}`
); );
@ -137,6 +137,12 @@ export default class CableDetailComponent extends Component {
}); });
}; };
dispense() {
this.props.socket.send(
`{"type": "cable_get","call": "send","data": {"position": ${this.state.cableDetails.position}}}`
);
}
componentDidMount() { componentDidMount() {
const cablePos = window.location.href.split("/").pop(); const cablePos = window.location.href.split("/").pop();
this.props.socket.send( this.props.socket.send(
@ -147,13 +153,10 @@ export default class CableDetailComponent extends Component {
handleMessage = (event) => { handleMessage = (event) => {
try { try {
console.log("Message from server", event.data);
const message = JSON.parse(event.data); const message = JSON.parse(event.data);
const cableDetails = new Cable(message.data.cables[0]); const cableDetails = new Cable(message.data.cables[0]);
this.setState({ cableDetails }); this.setState({ cableDetails });
} catch (error) { } catch (error) {}
console.error("Error parsing message from server:", error);
}
}; };
componentWillUnmount() { componentWillUnmount() {
@ -165,7 +168,6 @@ export default class CableDetailComponent extends Component {
try { try {
data = JSON.parse(object); data = JSON.parse(object);
} catch (error) { } catch (error) {
console.error("Error parsing JSON data:", error);
return <div>Error loading data...</div>; return <div>Error loading data...</div>;
} }
@ -231,13 +233,8 @@ export default class CableDetailComponent extends Component {
} }
render() { render() {
const { const { modalOpen_show, modalOpen_datasheet, modalOpacity, cableDetails } =
modalOpen_dispense, this.state;
modalOpen_show,
modalOpen_datasheet,
modalOpacity,
cableDetails,
} = this.state;
const modalStyle = { const modalStyle = {
content: { content: {
opacity: modalOpacity, opacity: modalOpacity,
@ -260,7 +257,7 @@ export default class CableDetailComponent extends Component {
"linear-gradient(-30deg, rgb(187, 194, 236) 0%, rgba(255, 255, 255, 1) 100%)", "linear-gradient(-30deg, rgb(187, 194, 236) 0%, rgba(255, 255, 255, 1) 100%)",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)", boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)",
minWidth: "30%", minWidth: "30%",
minHeight: "30%" minHeight: "30%",
}, },
overlay: { overlay: {
opacity: modalOpacity, opacity: modalOpacity,
@ -328,6 +325,19 @@ export default class CableDetailComponent extends Component {
{parseInt(cableDetails.position) + 1} {parseInt(cableDetails.position) + 1}
</div> </div>
</div> </div>
{cableDetails.qrcode !== DefaultQRImg ? (
<div className="cable-main-imageqr">
<img src={cableDetails.qrcode} alt="" />
</div>
) : (
<div
className="cable-main-imageqr"
src={cableDetails.qrcode}
alt=""
style={{ visibility: "hidden" }}
/>
)}
</div> </div>
) : ( ) : (
<div className="cable-main"></div> <div className="cable-main"></div>
@ -353,9 +363,14 @@ export default class CableDetailComponent extends Component {
</div> </div>
<div className="modal-datasheet"> <div className="modal-datasheet">
{cableDetails ? ( {cableDetails ? (
<iframe src={cableDetails.datasheet} height='70%' width='70%'></iframe>) : (<div className="datasheet"></div>) <iframe
} src={cableDetails.datasheet}
height="70%"
width="70%"
></iframe>
) : (
<div className="datasheet"></div>
)}
</div> </div>
<div <div
className="modal-close" className="modal-close"
@ -396,33 +411,11 @@ export default class CableDetailComponent extends Component {
</Modal> </Modal>
<div <div
className="cable-actions-button" className="cable-actions-button"
onClick={() => this.openModal("modalOpen_dispense")} onClick={() => this.dispense()}
> >
<span> Dispense</span> <span> Dispense</span>
<span>🔽</span> <span>🔽</span>
</div> </div>
<Modal
isOpen={modalOpen_dispense}
onRequestClose={() => this.closeModal("modalOpen_dispense")}
contentLabel="Dispense"
style={modalStyle}
>
<div className="modal-container">
<div className="modal-title">
<span>🔽</span>
<span>Dispensing Item</span>
</div>
<div className="modal-body">
<span>Please wait for your item to be dispensed.</span>
</div>
<div
className="modal-close"
onClick={() => this.closeModal("modalOpen_dispense")}
>
<span>Close</span>
</div>
</div>
</Modal>
</div> </div>
{cableDetails ? ( {cableDetails ? (

View File

@ -32,7 +32,6 @@ export default class MapComponent extends Component {
handleMessage = (event) => { handleMessage = (event) => {
try { try {
console.log("Message from server", event.data);
const message = JSON.parse(event.data); const message = JSON.parse(event.data);
const list = this.browseParse(message); const list = this.browseParse(message);
this.setState({ cableList: list }); this.setState({ cableList: list });
@ -40,9 +39,7 @@ export default class MapComponent extends Component {
this.select("0"); this.select("0");
this.updateSelection(); this.updateSelection();
}, 50); }, 50);
} catch (error) { } catch (error) {}
console.error("Error parsing message from server:", error);
}
}; };
updateSelection() { updateSelection() {

View File

@ -9,9 +9,9 @@ export default class NavBar extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
clicks: 0, modalOpen_activeArm: false,
modalOpen_return: false,
modalOpacity: 0, modalOpacity: 0,
mode: "idle",
}; };
this.openModal = this.openModal.bind(this); this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this); this.closeModal = this.closeModal.bind(this);
@ -28,37 +28,43 @@ export default class NavBar extends Component {
} else if (path.includes("cable")) { } else if (path.includes("cable")) {
document.getElementById("browse").style.backgroundColor = "#007CBE"; document.getElementById("browse").style.backgroundColor = "#007CBE";
document.getElementById("browse-s").style.color = "white"; document.getElementById("browse-s").style.color = "white";
} else if (path.includes("settings")) {
document.getElementById("settings").style.backgroundColor = "#007CBE";
document.getElementById("settings-s").style.color = "white";
} else { } else {
document.getElementById("browse").style.backgroundColor = "#007CBE"; document.getElementById("browse").style.backgroundColor = "#007CBE";
document.getElementById("browse-s").style.color = "white"; document.getElementById("browse-s").style.color = "white";
} }
this.props.socket.addEventListener("message", this.handleMessage);
} }
handleClick = () => {
const { clicks, timer } = this.state;
if (clicks === 0) {
const newTimer = setTimeout(() => {
this.setState({ clicks: 0 });
clearTimeout(newTimer);
}, 1000);
this.setState({ timer: newTimer });
}
this.setState({ clicks: clicks + 1 });
if (clicks + 1 === 2) {
window.location.replace("/settings");
clearTimeout(timer);
this.setState({ clicks: 0, timer: null });
}
};
componentWillUnmount() { componentWillUnmount() {
if (this.state.timer) { this.props.socket.removeEventListener("message", this.handleMessage);
clearTimeout(this.state.timer); }
handleMessage = (event) => {
try {
const message = JSON.parse(event.data);
if (message.type === "mode") {
let currentMode = JSON.parse(message.data).mode.toLowerCase();
this.setState({ mode: currentMode });
console.log("Current Mode: " + currentMode);
if (currentMode === "idle") {
setTimeout(() => {
console.log("State Mode: " + this.state.mode);
if (this.state.mode === "idle") {
this.closeModal("modalOpen_activeArm");
}
}, 1500);
} else {
this.openModal("modalOpen_activeArm");
} }
} }
} catch (error) {
console.error("");
}
};
openModal = (modal) => { openModal = (modal) => {
this.setState({ [modal]: true }, () => { this.setState({ [modal]: true }, () => {
@ -72,16 +78,20 @@ export default class NavBar extends Component {
}); });
}; };
returnCable = (tray) => { returnCable = () => {
this.props.socket.send( this.props.socket.send(
`{"type": "cable_get","call": "send","data": {"tray": ${tray}}}` `{"type": "cable_get","call": "send","data": {"tray": 0}}`
);
};
cancelAction = () => {
this.props.socket.send(
`{"type": "cancel_action","call": "request","data": {}}`
); );
console.log("Cable returned from tray " + tray);
this.closeModal("modalOpen_return");
}; };
render() { render() {
const { modalOpen_return, modalOpacity } = this.state; const { modalOpen_activeArm, modalOpacity } = this.state;
const modalStyle = { const modalStyle = {
content: { content: {
@ -105,7 +115,7 @@ export default class NavBar extends Component {
"linear-gradient(-30deg, rgb(187, 194, 236) 0%, rgba(255, 255, 255, 1) 100%)", "linear-gradient(-30deg, rgb(187, 194, 236) 0%, rgba(255, 255, 255, 1) 100%)",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)", boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)",
minWidth: "30%", minWidth: "30%",
minHeight: "30%" minHeight: "30%",
}, },
overlay: { overlay: {
opacity: modalOpacity, opacity: modalOpacity,
@ -120,7 +130,9 @@ export default class NavBar extends Component {
<div className="navbar-top"> <div className="navbar-top">
<div className="navbar-top-container"> <div className="navbar-top-container">
<div className="navbar-top-hamburger"></div> <div className="navbar-top-hamburger"></div>
<div className="navbar-top-secret" onClick={this.handleClick}></div> <NavLink className="navbar-settings" id="settings" to="/settings">
<span id="settings-s"></span>
</NavLink>
</div> </div>
<h1>Jukebox</h1> <h1>Jukebox</h1>
<ol className="navbar-list"> <ol className="navbar-list">
@ -139,45 +151,25 @@ export default class NavBar extends Component {
</NavLink> </NavLink>
</ol> </ol>
</div> </div>
<div <div className="navbar-return" onClick={() => this.returnCable()}>
className="navbar-return"
onClick={() => this.openModal("modalOpen_return")}
>
<span id="browse-s">Return Cable</span> <span id="browse-s">Return Cable</span>
</div> </div>
<Modal <Modal
isOpen={modalOpen_return} isOpen={modalOpen_activeArm}
onRequestClose={() => this.closeModal("modalOpen_return")}
contentLabel="show" contentLabel="show"
style={modalStyle} style={modalStyle}
> >
<div className="modal-container"> <div className="modal-container">
<div className="modal-title"> <div className="modal-title">
<span></span> <span></span>
<span>Return Cable</span> <span>Arm in Motion</span>
</div> </div>
<div className="modal-body"> <div className="modal-body">
<span>Select the tray you would like to return from.</span> <span>Please stay clear of the arm.</span>
</div> </div>
<div className="modal-tray"> <div className="modal-closeX" onClick={() => this.cancelAction()}>
<div className="modal-return" onClick={() => this.returnCable(0)}> <span>Cancel Action</span>
<span>1</span>
</div>
<div className="modal-return" onClick={() => this.returnCable(1)}>
<span>2</span>
</div>
<div className="modal-return" onClick={() => this.returnCable(2)}>
<span>3</span>
</div>
<div className="modal-return" onClick={() => this.returnCable(3)}>
<span>4</span>
</div>
</div>
<div
className="modal-close"
onClick={() => this.closeModal("modalOpen_return")}
>
<span>Cancel</span>
</div> </div>
</div> </div>
</Modal> </Modal>

View File

@ -1,19 +1,114 @@
import React, { Component } from "react"; import React, { Component } from "react";
import BeldenLogo from "../assets/images/belden-white.png"; import BeldenLogo from "../assets/images/belden-white.png";
import Modal from "react-modal";
import "../assets/stylesheets/settings.scss"; import "../assets/stylesheets/settings.scss";
Modal.setAppElement("#root");
export default class SettingsComponent extends Component { export default class SettingsComponent extends Component {
shutdownPower = () => { constructor(props) {
console.log("Shutting down..."); super(props);
this.props.socket.send('{"type":"shutdown","call":"request","data":{}}'); this.state = {
modalOpen_quickAction: false,
modalOpacity: 0,
action: "",
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
quickAction = (action, requirePrompt) => {
if (requirePrompt) {
this.openModal("modalOpen_quickAction", action);
} else {
this.quickActionPerform(action);
}
}; };
restartPower = () => { quickActionPerform = (action) => {
switch (action) {
case "shutdown":
console.log("Shutting down...");
this.props.socket.send(
'{"type":"shutdown","call":"request","data":{}}'
);
break;
case "restart":
console.log("Restarting..."); console.log("Restarting...");
this.props.socket.send('{"type":"restart","call":"request","data":{}}'); this.props.socket.send('{"type":"restart","call":"request","data":{}}');
break;
case "home":
console.log("Homing...");
this.props.socket.send('{"type":"home","call":"request","data":{}}');
break;
default:
console.log("Invalid action");
break;
}
};
openModal = (modal, action) => {
this.setState({ [modal]: true }, () => {
setTimeout(() => this.setState({ modalOpacity: 1 }), 100);
});
this.setState({ action });
};
closeModal = (modal) => {
this.setState({ modalOpacity: 0 }, () => {
setTimeout(() => this.setState({ [modal]: false }), 300);
});
};
performActionCloseModal = () => {
console.log("Performing action: " + this.state.action);
this.quickActionPerform(this.state.action);
this.closeModal("modalOpen_quickAction");
};
sendObject = () => {
const object = document.getElementById("sendobject").value;
console.log("Sending object: " + object);
this.props.socket.send
? this.props.socket.send(object)
: console.log("No socket connection");
}; };
render() { render() {
const { modalOpen_quickAction, modalOpacity } = this.state;
const modalStyle = {
content: {
opacity: modalOpacity,
transition: "opacity 300ms ease-in-out",
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
width: "auto",
height: "auto",
transform: "translate(-50%, -50%)",
overflow: "hidden",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
borderRadius: "20px",
background:
"linear-gradient(-30deg, rgb(187, 194, 236) 0%, rgba(255, 255, 255, 1) 100%)",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)",
minWidth: "30%",
minHeight: "30%",
},
overlay: {
opacity: modalOpacity,
transition: "opacity 300ms ease-in-out",
backgroundColor: "rgba(255, 255, 255, 0.15)",
backdropFilter: "blur(5px)",
},
};
return ( return (
<div className="settings"> <div className="settings">
<div className="settings-image"> <div className="settings-image">
@ -21,88 +116,227 @@ export default class SettingsComponent extends Component {
</div> </div>
<div className="settings-fieldContainer"> <div className="settings-fieldContainer">
<h1 className="settings-title"> Settings</h1> <h1 className="settings-title"> Settings</h1>
<div className="settings-powerContainer"> <div className="settings-grid">
<h2>Quick Actions:</h2>
<div className="settings-gridInner">
<div <div
className="settings-powerButton" className="settings-button"
onClick={() => this.shutdownPower()} onClick={() => this.quickAction("shutdown", true)}
> >
<span>🔴 Power Off</span> <span>🔴 Power Off</span>
</div> </div>
{/* <div <div
className="settings-powerButton" className="settings-button"
onClick={() => this.restartPower()} onClick={() => this.quickAction("restart", false)}
> >
<span>🟨 Restart</span> <span>🟠 Restart</span>
</div> */}
</div> </div>
<div className="settings-creditsContainer"> <div
<div className="settings-credits"> className="settings-button"
<h2 className="settings-credits-title">Credits:</h2> onClick={() => this.quickAction("home", false)}
<div className="entry">
<span className="entry-name">Cole Deck,</span>
<span className="entry-position">Project Lead,</span>
<a className="entry-links" href="https://deck.sh">
https://deck.sh
</a>
</div>
<div className="entry">
<span className="entry-name">Natorion Johnson,</span>
<span className="entry-position">Lead PCB assembler,</span>
<a
className="entry-links"
href="https://linkedin.com/in/NatorionJ"
> >
https://linkedin.com/in/NatorionJ <span>🏠 Home Arm</span>
</a>
</div> </div>
<div className="entry"> </div>
<span className="entry-name">Fannie Yu,</span> </div>
<span className="entry-position"> <div className="settings-grid">
CAD Design, Fabrication Planner <h2>💻Send Object:</h2>
</span> <div className="settings-gridInner">
<a <form className="settings-form">
className="entry-links" <input
href="https://linkedin.com/in/fannieyu" id="sendobject"
type="text"
name="sendobject"
placeholder={`{"type":"cable_map","call":"request","data":{}}`}
/>
<div
className="settings-button"
id="sendobjectButton"
onClick={() => this.sendObject()}
> >
https://linkedin.com/in/fannieyu <span>Send</span>
</a>
</div> </div>
<div className="entry"> </form>
<span className="entry-name">Elias Frey Reschly,</span>
<span className="entry-position">
Mechanical Design, Fabrication
</span>
<div className="entry-links"></div>
</div> </div>
<div className="entry">
<span className="entry-name">Scarlett Kadan,</span>
<span className="entry-position">
Front-End Dev, UI/UX Designer,
</span>
<a className="entry-links" href="https://kadan.live">
https://kadan.live
</a>
</div> </div>
<div className="settings-grid">
<h2>Credits:</h2>
<div id="creditsgrid" className="settings-gridInner">
<div className="entry"> <div className="entry">
<span className="entry-name">Lucas Ferguson,</span> <div className="entry-image">
<span className="entry-position">Front-End Dev,</span> <img
<a className="entry-img"
className="entry-links" src={require("../assets/images/pic_cole.jpg")}
href="https://lucasferguson.webflow.io" alt="Cole Deck"
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_cole.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Cole Deck</h2>
<h3>Project Lead</h3>
</div>
</div>
<div className="entry">
<div className="entry-image">
<img
className="entry-img"
src={require("../assets/images/pic_scarlett.jpg")}
alt="Scarlett Kadan"
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_scarlett.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Scarlett Kadan</h2>
<h3>Lead Front-End Dev, UI/UX Designer</h3>
</div>
</div>
<div className="entry">
<div className="entry-image">
<img
className="entry-img"
src={require("../assets/images/pic_natorion.jpg")}
alt="Natorion Johnson"
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_natorion.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Natorion Johnson</h2>
<h3>Lead PCB assembler</h3>
</div>
</div>
<div className="entry">
<div className="entry-image">
<img
className="entry-img"
src={require("../assets/images/pic_fannie.jpeg")}
alt="Fannie Yu"
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_fannie.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Fannie Yu</h2>
<h3>CAD Design, Fabrication Planner</h3>
</div>
</div>
<div className="entry">
<div className="entry-image">
<img
className="entry-img"
src={require("../assets/images/pic_elias.jpg")}
alt="Elias Reschly"
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_elias.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Elias Reschly</h2>
<h3>Mechanical Design, Fabrication</h3>
</div>
</div>
<div className="entry">
<div className="entry-image">
<img
className="entry-img"
src={require("../assets/images/pic_lucas.jpg")}
alt="Lucas Ferguson"
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_lucas.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Lucas Ferguson</h2>
<h3>Front-End Dev</h3>
</div>
</div>
<div className="entry">
<div className="entry-image">
<img
className="entry-img"
src={require("../assets/images/pic_dustin.jpg")}
alt=""
/>
<div className="entry-qr">
<img
src={require("../assets/images/qr_dustin.png")}
alt="QR"
/>
</div>
</div>
<div className="entry-title">
<h2>Dustin Thomas</h2>
<h3>Back-End Dev</h3>
</div>
</div>
</div>
</div>
</div>
<Modal
isOpen={modalOpen_quickAction}
contentLabel="show"
onRequestClose={() => this.closeModal("modalOpen_quickAction")}
style={modalStyle}
> >
https://lucasferguson.webflow.io <div className="modal-container">
</a> <div className="modal-title">
</div> <span></span>
<div className="entry"> <span>Warning</span>
<span className="entry-name">Dustin Thomas,</span>
<span className="entry-position">Back-End Dev,</span>
<a className="entry-links" href="https://cptlobster.dev">
https://cptlobster.dev
</a>
</div> </div>
<div className="modal-body">
<span>Are you sure you want to perform this quick action?</span>
</div>
<div className="modal-tray">
<div
className="modal-return"
onClick={() =>
this.performActionCloseModal("modalOpen_quickAction")
}
>
<span>Continue</span>
</div>
<div
className="modal-return"
onClick={() => this.closeModal("modalOpen_quickAction")}
>
<span>Cancel</span>
</div> </div>
</div> </div>
</div> </div>
</Modal>
</div> </div>
); );
} }

View File

@ -14,7 +14,7 @@ export default class StatisticsComponent extends Component {
<div className="statistics-grid"> <div className="statistics-grid">
<div className="statistics-grid-container"> <div className="statistics-grid-container">
<iframe <iframe
src="http://172.31.108.29:3000/d-solo/cdiqwmlr8c9ogf/sensors?orgId=1&refresh=1s&theme=light&panelId=8" src="http://192.168.1.12:3000/d-solo/cdiqwmlr8c9ogf/sensors?orgId=1&refresh=1s&theme=light&panelId=8"
title="Belden" title="Belden"
className="statistics-iframe" className="statistics-iframe"
/> />

View File

@ -2,10 +2,6 @@ import React, { Component } from "react";
import NavBar from "../components/NavBar"; import NavBar from "../components/NavBar";
import StatisticsComponent from "../components/StatisticsComponent"; import StatisticsComponent from "../components/StatisticsComponent";
import "../assets/stylesheets/app.scss"; import "../assets/stylesheets/app.scss";
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
export default class StatisticsRoute extends Component { export default class StatisticsRoute extends Component {
constructor(props) { constructor(props) {
@ -17,11 +13,7 @@ export default class StatisticsRoute extends Component {
return ( return (
<div className="container"> <div className="container">
<NavBar socket={this.props.socket} /> <NavBar socket={this.props.socket} />
<Provider> <StatisticsComponent socket={this.props.socket} />
<KeepAlive name="Grafana">
<StatisticsComponent socketHandler={this.props.socket} />
</KeepAlive>
</Provider>
</div> </div>
); );
} }

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import DefaultPartImg from "../assets/images/part.png"; import DefaultPartImg from "../assets/images/part.png";
import DefaultQRImg from "../assets/images/default_qr.png";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import "../assets/stylesheets/browse.scss"; import "../assets/stylesheets/browse.scss";
@ -15,7 +16,8 @@ export default class cable {
short_description, short_description,
image, image,
category, category,
application application,
qrcode
) { ) {
this.part_number = part_number; this.part_number = part_number;
this.position = position; this.position = position;
@ -28,6 +30,8 @@ export default class cable {
this.short_description = short_description; this.short_description = short_description;
this.description = description; this.description = description;
this.qrcode = qrcode ? `http://${hostname}${qrcode}` : DefaultQRImg;
if (short_description === undefined) { if (short_description === undefined) {
if (this.description !== undefined) { if (this.description !== undefined) {
this.short_description = this.description; this.short_description = this.description;