diff --git a/client/src/components/common/Button.js b/client/src/components/common/Button.js
index cd2e5384..53ef599b 100644
--- a/client/src/components/common/Button.js
+++ b/client/src/components/common/Button.js
@@ -1,9 +1,15 @@
import React from "react";
import styled, { css } from "styled-components";
import PropTypes from "prop-types";
+import LoadingDots from "./animation/LoadingDots";
-const Button = ({ children, ...props }) => {
- return {children};
+const Button = ({ children, loading, onClick, ...props }) => {
+ const clickHandler = loading ? undefined : onClick;
+ return (
+
+ {loading ? : children}
+
+ );
};
Button.propTypes = {
@@ -13,6 +19,8 @@ Button.propTypes = {
secondary: PropTypes.bool,
/* Makes the button width === 100% */
autoWidth: PropTypes.bool,
+ /* Replaces the button label with a loading indicator and prevents onClick */
+ loading: PropTypes.bool,
};
export default Button;
@@ -22,8 +30,11 @@ const Btn = styled.button`
border: none;
border-radius: 4px;
padding: 5px 12px;
- font-size: 14px;
+ font-size: 16px;
width: ${(props) => props.autoWidth && "100%"};
+ display: flex;
+ justify-content: center;
+ align-items: center;
// If secondary prop === true
${(props) =>
@@ -41,7 +52,7 @@ const Btn = styled.button`
${(props) =>
props.primary &&
css`
- padding: 7px 12px;
+ padding: 9px 12px;
border-radius: 3px;
background-color: #4a86fa;
color: #fff;
diff --git a/client/src/components/common/Errors.js b/client/src/components/common/Errors.js
new file mode 100644
index 00000000..dc761f7c
--- /dev/null
+++ b/client/src/components/common/Errors.js
@@ -0,0 +1,27 @@
+import React from "react";
+import PropTypes from "prop-types";
+
+const Errors = ({ errors, margin }) => {
+ console.log(errors);
+ if (!errors || errors.length < 1) {
+ return null;
+ }
+ return (
+
+ {errors.map((err, index) => (
+
+ {err}
+
+ ))}
+
+ );
+};
+
+export default Errors;
+
+Errors.propTypes = {
+ /* Array of strings containing error messages */
+ errors: PropTypes.arrayOf(PropTypes.string),
+ /* Top margin for error div */
+ margin: PropTypes.number,
+};
diff --git a/client/src/components/common/Input.js b/client/src/components/common/Input.js
index f358e03b..958b1855 100644
--- a/client/src/components/common/Input.js
+++ b/client/src/components/common/Input.js
@@ -31,7 +31,7 @@ const StyledInput = styled.input`
border: 1px solid #818181;
background-color: #fff;
border-radius: 4px;
- font-size: 14px;
+ font-size: 16px;
padding: 7px 9px;
width: 100%;
`;
diff --git a/client/src/components/common/InputLabel.js b/client/src/components/common/InputLabel.js
index c370796b..667159b8 100644
--- a/client/src/components/common/InputLabel.js
+++ b/client/src/components/common/InputLabel.js
@@ -8,7 +8,8 @@ const InputLabel = ({ children, margin }) => {
export default InputLabel;
-const Label = styled.h5`
- font-size: 14px;
+const Label = styled.h3`
+ font-size: 16px;
+ font-weight: 500;
margin: ${(props) => props.margin || "13px 0 7px 0"};
`;
diff --git a/client/src/components/common/Modal.js b/client/src/components/common/Modal.js
index 71fc9c8a..682d962d 100644
--- a/client/src/components/common/Modal.js
+++ b/client/src/components/common/Modal.js
@@ -42,7 +42,7 @@ const Content = styled.div`
position: relative;
background-color: #fff;
margin: 15% auto;
- padding: 20px;
+ padding: 35px 20px;
border-radius: 4px;
box-shadow: 3px 3px 9px #48484830;
width: ${(props) => props.width || "520px"};
diff --git a/client/src/components/common/SearchBar.js b/client/src/components/common/SearchBar.js
index 58bf432c..c9e8b1b8 100644
--- a/client/src/components/common/SearchBar.js
+++ b/client/src/components/common/SearchBar.js
@@ -14,7 +14,7 @@ const SearchBar = ({ onChange, placeholder }) => {
export default SearchBar;
const SearchDiv = styled.div`
- height: 26px;
+ height: 32px;
align-items: center;
border-radius: 3px;
max-width: 360px;
@@ -36,6 +36,7 @@ const TextInput = styled.input`
background-color: transparent;
width: 100%;
padding-left: 11px;
+ font-size: 16px;
&:focus {
outline: none;
diff --git a/client/src/components/common/Select.js b/client/src/components/common/Select.js
index 6ea00027..2e3aafcc 100644
--- a/client/src/components/common/Select.js
+++ b/client/src/components/common/Select.js
@@ -23,13 +23,13 @@ const customStyles = {
...provided,
// none of react-select's styles are passed to
border: "1px solid #818181",
- fontSize: 14,
- height: 33,
- minHeight: 33,
+ fontSize: 16,
+ height: 35,
+ minHeight: 35,
}),
valueContainer: (provided) => ({
...provided,
- height: 33,
+ height: 35,
padding: "0 4px",
}),
@@ -42,7 +42,7 @@ const customStyles = {
}),
indicatorsContainer: (provided, state) => ({
...provided,
- height: "33px",
+ height: "35px",
padding: "8px",
}),
};
diff --git a/client/src/components/common/animation/LoadingDots.js b/client/src/components/common/animation/LoadingDots.js
new file mode 100644
index 00000000..8f5190d7
--- /dev/null
+++ b/client/src/components/common/animation/LoadingDots.js
@@ -0,0 +1,49 @@
+import React from "react";
+import styled from "styled-components";
+
+const LoadingDots = ({ size = 8, color }) => {
+ return (
+
+
+
+
+
+ );
+};
+
+export default LoadingDots;
+
+const Wrapper = styled.div`
+ display: flex;
+
+ div {
+ background-color: ${(props) => props.color || "#fff"};
+ }
+`;
+
+const Dot = styled.div`
+ height: ${(props) => props.size + "px"};
+ width: ${(props) => props.size + "px"};
+ border-radius: ${(props) => props.size / 2 + "px"};
+ margin: ${(props) => props.size * 0.3 + "px"};
+
+ @keyframes inout {
+ from {
+ transform: scale(1);
+ }
+
+ 50% {
+ transform: scale(1.35);
+ }
+
+ to {
+ transform: scale(1);
+ }
+ }
+
+ animation-name: inout;
+ animation-delay: ${(props) => props.delay + "ms"};
+ animation-iteration-count: infinite;
+ animation-direction: forward;
+ animation-duration: 850ms;
+`;
diff --git a/client/src/components/courses/CreateCourse.js b/client/src/components/courses/CreateCourse.js
index dd9a2515..ff5b9716 100644
--- a/client/src/components/courses/CreateCourse.js
+++ b/client/src/components/courses/CreateCourse.js
@@ -1,22 +1,16 @@
import React, { useState } from "react";
import styled from "styled-components";
import Button from "../common/Button";
-import Input from "../common/Input";
-import InputLabel from "../common/InputLabel";
import Modal from "../common/Modal";
-import Select from "../common/Select";
-
-const INVITE_OPTIONS = [
- {
- label: "Share Link / Access Code",
- value: "code",
- description:
- "Anyone with the link or access code can join. Share the link / code below with students.",
- },
-];
+import CourseConfirmation from "./createCourse/CourseConfirmation";
+import CourseInfo from "./createCourse/CourseInfo";
const CreateCourse = () => {
const [modalIsShown, toggleModal] = useState(false);
+ // Course is set by the CourseInfo component when instructors create the course
+ // The info is used to share the course link/access code provided by the API
+ const [course, setCourse] = useState(null);
+
return (
<>