diff --git a/.gitignore b/.gitignore index 2cd0c01c..c094933b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -.vscode \ No newline at end of file +.vscode +.idea + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..877839d2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ + +src/* +src/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6891fbef..d9caa348 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,13 +15,15 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-modal": "^3.16.1", + "react-password-checklist": "^1.8.1", "react-router-dom": "^6.8.0", "react-scripts": "5.0.1", + "reactjs-popup": "^2.0.6", "web-vitals": "^3.1.1" }, "devDependencies": { "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", + "eslint-config-prettier": "^9.1.2", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-n": "^16.6.2", @@ -7360,9 +7362,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "license": "MIT", "bin": { @@ -14974,6 +14976,15 @@ "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" } }, + "node_modules/react-password-checklist": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/react-password-checklist/-/react-password-checklist-1.8.1.tgz", + "integrity": "sha512-QHIU/OejxoH4/cIfYLHaHLb+yYc8mtL0Vr4HTmULxQg3ZNdI9Ni/yYf7pwLBgsUh4sseKCV/GzzYHWpHqejTGw==", + "license": "MIT", + "peerDependencies": { + "react": ">16.0.0-alpha || >17.0.0-alpha || >18.0.0-alpha" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -15084,6 +15095,19 @@ } } }, + "node_modules/reactjs-popup": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/reactjs-popup/-/reactjs-popup-2.0.6.tgz", + "integrity": "sha512-A+tt+x9wdgZiZjv0e2WzYLD3IfFwJALaRaqwrCSXGjo0iQdsry/EtBEbQXRSmQs7cHmOi5eytCiSlOm8k4C+dg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 249b6b05..1825e548 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-modal": "^3.16.1", + "react-password-checklist": "^1.8.1", "react-router-dom": "^6.8.0", "react-scripts": "5.0.1", + "reactjs-popup": "^2.0.6", "web-vitals": "^3.1.1" }, "scripts": { @@ -43,7 +45,7 @@ }, "devDependencies": { "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", + "eslint-config-prettier": "^9.1.2", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-n": "^16.6.2", diff --git a/src/App.css b/src/App.css index ec62bd1a..1222108c 100644 --- a/src/App.css +++ b/src/App.css @@ -14,3 +14,8 @@ .ReactModal__Html--open { overflow: hidden; } + +.border-line { + border-bottom: 1px solid var(--color-blue5); + padding: 20px 10px; +} diff --git a/src/App.js b/src/App.js index 136c3a15..0a4b97d5 100644 --- a/src/App.js +++ b/src/App.js @@ -8,18 +8,21 @@ import Verification from './pages/verification'; import { AuthProvider, ProtectedRoute } from './context/auth'; import { ModalProvider } from './context/modal'; import Welcome from './pages/welcome'; +import { FormProvider } from './context/form'; +import Cohort from './pages/cohort'; + const App = () => { return ( <> + } /> } /> } /> } /> - { } /> + + + + } + /> + ); diff --git a/src/components/dropdown/index.js b/src/components/dropdown/index.js new file mode 100644 index 00000000..9149a65e --- /dev/null +++ b/src/components/dropdown/index.js @@ -0,0 +1,75 @@ +import React, { useState, useRef, useEffect } from "react"; + +function DropdownMenu({ + label, + options = [], + value, + onChange, + placeholder = "Select an option", +}) { + const [isOpen, setIsOpen] = useState(false); + const dropdownRef = useRef(null); + + const toggleDropdown = () => setIsOpen((prev) => !prev); + + const handleOptionClick = (optionValue) => { + onChange(optionValue); + setIsOpen(false); + }; + + const handleClickOutside = (event) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setIsOpen(false); + } + }; + + useEffect(() => { + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + const normalizedOptions = Array.isArray(options) + ? options.map((opt) => + typeof opt === "object" + ? { label: opt.label, value: opt.value } + : { label: opt, value: opt } + ) + : []; + + const selectedOption = normalizedOptions.find((opt) => opt.value === value); + + return ( +
+ {label && } + + + {isOpen && ( + + )} +
+ ); +} + +export default DropdownMenu; diff --git a/src/components/dropdown/style.css b/src/components/dropdown/style.css new file mode 100644 index 00000000..9619e527 --- /dev/null +++ b/src/components/dropdown/style.css @@ -0,0 +1,45 @@ +/* Dropdown Button */ +.dropbtn { + background-color: #3498DB; + color: white; + padding: 16px; + font-size: 16px; + border: none; + cursor: pointer; +} + +/* Dropdown button on hover & focus */ +.dropbtn:hover, .dropbtn:focus { + background-color: #2980B9; +} + +/* The container
- needed to position the dropdown content */ +.dropdown { + position: relative; + left: 0; + display: inline-block; +} + +/* Dropdown Content (Hidden by Default) */ +.dropdown-content { + display: none; + position: absolute; + background-color: #f1f1f1; + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; +} + +/* Links inside the dropdown */ +.dropdown-content a { + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; +} + +/* Change color of dropdown links on hover */ +.dropdown-content a:hover {background-color: #ddd;} + +/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */ +.show {display:block;} \ No newline at end of file diff --git a/src/components/form/numberInput/index.js b/src/components/form/numberInput/index.js new file mode 100644 index 00000000..00205226 --- /dev/null +++ b/src/components/form/numberInput/index.js @@ -0,0 +1,25 @@ + +const NumberInput = ({ value, onChange, name, label, icon, type = 'number',placeholder}) => { + + return ( +
+ {label && } + { + if (e.target.value.length > 11) { + e.target.value = e.target.value.slice(0, 11); + }}} + /> + {icon && {icon}} +
+ ); + } + +export default NumberInput; \ No newline at end of file diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index 39da3cae..06d7feb5 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,8 +1,8 @@ import { useState } from 'react'; -const TextInput = ({ value, onChange, name, label, icon, type = 'text' }) => { - const [input, setInput] = useState(''); +const TextInput = ({ value, onChange, name, label, icon, type = 'text', placeholder }) => { const [showpassword, setShowpassword] = useState(false); + const [input, setInput] = useState(value); if (type === 'password') { return (
@@ -11,9 +11,10 @@ const TextInput = ({ value, onChange, name, label, icon, type = 'text' }) => { type={type} name={name} value={value} + placeholder = {placeholder} onChange={(e) => { onChange(e); - setInput(e.target.value); + setInput(e.target.value) }} /> {showpassword && } @@ -22,6 +23,7 @@ const TextInput = ({ value, onChange, name, label, icon, type = 'text' }) => { onClick={(e) => { e.preventDefault(); setShowpassword(!showpassword); + }} > @@ -36,6 +38,7 @@ const TextInput = ({ value, onChange, name, label, icon, type = 'text' }) => { type={type} name={name} value={value} + placeholder = {placeholder} onChange={onChange} className={icon && 'input-has-icon'} /> @@ -43,7 +46,7 @@ const TextInput = ({ value, onChange, name, label, icon, type = 'text' }) => {
); } -}; +} const EyeLogo = () => { return ( diff --git a/src/components/navigation/index.js b/src/components/navigation/index.js index b31393a8..10eec500 100644 --- a/src/components/navigation/index.js +++ b/src/components/navigation/index.js @@ -28,7 +28,7 @@ const Navigation = () => {
  • - +

    Cohort

    diff --git a/src/components/posts/index.js b/src/components/posts/index.js index 79756c41..f68a3450 100644 --- a/src/components/posts/index.js +++ b/src/components/posts/index.js @@ -6,17 +6,32 @@ const Posts = () => { const [posts, setPosts] = useState([]); useEffect(() => { - getPosts().then(setPosts); + async function fetchPosts() { + try { + const posts = await getPosts(); + setPosts(posts); + } catch (error) { + console.error('Error fetching posts:', error); + setPosts([]); + } + } + fetchPosts(); }, []); + return ( <> {posts.map((post) => { + // Handle missing author gracefully + const authorName = post.author + ? `${post.author.first_name || 'Unknown'} ${post.author.last_name || 'User'}` + : 'Unknown User'; + return ( diff --git a/src/components/profile-icon/index.js b/src/components/profile-icon/index.js new file mode 100644 index 00000000..02eaf3cf --- /dev/null +++ b/src/components/profile-icon/index.js @@ -0,0 +1,33 @@ +import './style.css'; +import SeeProfile from '../seeProfile'; +import Popup from 'reactjs-popup'; + +const UserIcon = ({initials, firstname, lastname, role}) => { + + return ( +
    +
    +
    +

    {initials}

    +
    +
    +
    +

    {firstname} {lastname}

    +

    {role}

    +
    + +

    ...

    } position="right center" + closeOnDocumentClick + arrow={false}> + + +
  • + ) +} + +export default UserIcon; \ No newline at end of file diff --git a/src/components/profile-icon/style.css b/src/components/profile-icon/style.css new file mode 100644 index 00000000..a0dcbd6c --- /dev/null +++ b/src/components/profile-icon/style.css @@ -0,0 +1,40 @@ +.user { + display: flex; + align-items: center; + padding: 8px 12px; + gap: 12px; +} + +.user-info { + display: flex; + flex-direction: column; + flex: 1 1 auto; + min-width: 0; +} + +.profile-circle{ + min-width: 40px; + height: 40px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + background: #4cc0e5; +} + + +.user-name { + margin: 0; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.pop-up { + position: absolute; + top: 100%; /* under .edit-icon */ + right: 0; /* høyrejustert med ikonet */ + margin-top: 8px; + z-index: 100; +} \ No newline at end of file diff --git a/src/components/seeProfile/index.js b/src/components/seeProfile/index.js new file mode 100644 index 00000000..bc8888df --- /dev/null +++ b/src/components/seeProfile/index.js @@ -0,0 +1,37 @@ +import Card from '../card'; +import './style.css'; +import { NavLink } from 'react-router-dom'; +import ProfileIcon from '../../assets/icons/profileIcon'; + +const SeeProfile = ({initials, firstname, lastname, role}) => { + + return ( +
    + +
    +
    +

    {initials}

    +
    + +
    +

    {firstname} {lastname}

    + {role}, Cohort 3 +
    +
    + +
    +
      +
    • + +

      Profile

      +
      +
    • +
    +
    +
    +
    + ) + +} + +export default SeeProfile; \ No newline at end of file diff --git a/src/components/seeProfile/style.css b/src/components/seeProfile/style.css new file mode 100644 index 00000000..0b4797a9 --- /dev/null +++ b/src/components/seeProfile/style.css @@ -0,0 +1,5 @@ + + +.card { + width: 450px; +} \ No newline at end of file diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index c9e5f259..3f745c15 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -4,7 +4,7 @@ import Button from '../button'; import './style.css'; import { useState } from 'react'; -const Stepper = ({ header, children, onComplete }) => { +const Stepper = ({ header, children, onComplete, data }) => { const [currentStep, setCurrentStep] = useState(0); const onBackClick = () => { @@ -22,6 +22,33 @@ const Stepper = ({ header, children, onComplete }) => { setCurrentStep(currentStep + 1); }; + const validateName = (data) => { + if(!data) { + alert("OBSS!!! Please write first_name and last_name") + return false + } else { + return true + } + } + + const validateUsername = (data) => { + if(data.username.length < 7) { + alert("Username is too short. Input must be at least 7 characters long") + return false + } else { + return true + } + } + + const validateMobile = (data) => { + if(data.length < 8) { + alert("Mobile number is too short. Input must be at least 8 characters long") + return false + } else { + return true + } + } + return ( {header} @@ -33,14 +60,34 @@ const Stepper = ({ header, children, onComplete }) => {
    ); }; -export default Stepper; +export default Stepper; \ No newline at end of file diff --git a/src/context/auth.js b/src/context/auth.js index 47cd66c9..94f6fe94 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -19,7 +19,7 @@ const AuthProvider = ({ children }) => { useEffect(() => { const storedToken = localStorage.getItem('token'); - if (storedToken) { + if (storedToken && !token) { setToken(storedToken); navigate(location.state?.from?.pathname || '/'); } @@ -34,8 +34,8 @@ const AuthProvider = ({ children }) => { localStorage.setItem('token', res.data.token); - setToken(res.token); - navigate(location.state?.from?.pathname || '/'); + setToken(res.data.token); + navigate(location.state?.from?.pathname || '/'); }; const handleLogout = () => { @@ -45,15 +45,17 @@ const AuthProvider = ({ children }) => { const handleRegister = async (email, password) => { const res = await register(email, password); - setToken(res.data.token); + + localStorage.setItem('token', res.data.token); + setToken(res.data.token); navigate('/verification'); }; - const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => { + const handleCreateProfile = async (first_name, last_name, username, github_username, mobile, bio, role, specialism, cohort, start_date, end_date, photo) => { const { userId } = jwt_decode(token); - await createProfile(userId, firstName, lastName, githubUrl, bio); + await createProfile(userId, first_name, last_name, username, github_username, mobile, bio, role, specialism, cohort, start_date, end_date, photo); localStorage.setItem('token', token); navigate('/'); diff --git a/src/context/form.js b/src/context/form.js new file mode 100644 index 00000000..c602786e --- /dev/null +++ b/src/context/form.js @@ -0,0 +1,15 @@ +import React, { createContext, useContext, useState } from 'react'; + +const FormContext = createContext(); + +export const FormProvider = ({ children }) => { + const [formData, setFormData] = useState({ email: '', password: '' }); + + return ( + + {children} + + ); +}; + +export const useFormData = () => useContext(FormContext); diff --git a/src/pages/cohort/cohort.css b/src/pages/cohort/cohort.css new file mode 100644 index 00000000..e69de29b diff --git a/src/pages/cohort/exercises/exercises.css b/src/pages/cohort/exercises/exercises.css new file mode 100644 index 00000000..e8764745 --- /dev/null +++ b/src/pages/cohort/exercises/exercises.css @@ -0,0 +1,27 @@ +.value { + color: var(--color-blue1); + margin-bottom: 15px; +} + +.label { + color: var(--color-blue1); + margin-bottom: 15px; +} + +.see-more-button { + background-color: var(--color-blue5); +} + +.exercise-row { + display: flex; + justify-content: space-between; + margin-bottom: 8px; +} + +.label { + font-weight: 500; +} + +.value { + color: var(--color-blue1); +} diff --git a/src/pages/cohort/exercises/index.js b/src/pages/cohort/exercises/index.js new file mode 100644 index 00000000..e1b6a573 --- /dev/null +++ b/src/pages/cohort/exercises/index.js @@ -0,0 +1,32 @@ +import Card from "../../../components/card"; +import './exercises.css' + +const Exercises = () => { + return ( + <> + +

    My Exercises

    +
    + +
    + Modules: + 2/7 completed +
    + +
    + Units: + 4/10 completed +
    + +
    + Exercise: + 34/58 completed +
    + + +
    + + ) +} + +export default Exercises; \ No newline at end of file diff --git a/src/pages/cohort/index.js b/src/pages/cohort/index.js new file mode 100644 index 00000000..302b0748 --- /dev/null +++ b/src/pages/cohort/index.js @@ -0,0 +1,19 @@ +import Teachers from './teachers'; +import Exercises from "./exercises"; + +const Cohort = () => { + return ( + <> +
    + +
    + + + ) + +} + +export default Cohort; diff --git a/src/pages/cohort/students/index.js b/src/pages/cohort/students/index.js new file mode 100644 index 00000000..1a0b5886 --- /dev/null +++ b/src/pages/cohort/students/index.js @@ -0,0 +1,7 @@ +function Students() { + return ( + <> + ) +} + +export default Students; \ No newline at end of file diff --git a/src/pages/cohort/teachers/index.js b/src/pages/cohort/teachers/index.js new file mode 100644 index 00000000..ea621275 --- /dev/null +++ b/src/pages/cohort/teachers/index.js @@ -0,0 +1,19 @@ +import Card from "../../../components/card"; +import './style.css'; +import UserIcon from "../../../components/profile-icon"; + +const Teachers = () => { + + return ( + <> + +

    Teachers

    +
    + +
    +
    + + ); +} + +export default Teachers; diff --git a/src/pages/cohort/teachers/style.css b/src/pages/cohort/teachers/style.css new file mode 100644 index 00000000..9323386a --- /dev/null +++ b/src/pages/cohort/teachers/style.css @@ -0,0 +1,8 @@ +.card { + background: white; + padding: 24px; + border-radius: 8px; + width: 50%; + margin-bottom: 25px; + border: 1px #e6ebf5 solid; +} \ No newline at end of file diff --git a/src/pages/login/index.js b/src/pages/login/index.js index 08df7d5a..1dcb7382 100644 --- a/src/pages/login/index.js +++ b/src/pages/login/index.js @@ -36,7 +36,16 @@ const Login = () => { } modal> + {close => ( + +
    +

    + {data.photo ? "Replace Photo" : "Upload Photo"} +

    +

    Choose a file to upload your headshot

    + +
    + + + handleFileChange(e, close)} + /> + +
    +
    +
    + )} + + +

    Please upload a valid image file

    + + -

    *Required

    diff --git a/src/pages/welcome/stepThree/index.js b/src/pages/welcome/stepThree/index.js new file mode 100644 index 00000000..de8daf58 --- /dev/null +++ b/src/pages/welcome/stepThree/index.js @@ -0,0 +1,46 @@ +import Form from '../../../components/form'; +import TextInput from '../../../components/form/textInput'; + +const StepThree = ({ data, setData }) => { + + + return ( + <> +
    +

    Training info

    +
    + +
    + + + + + +

    *Required

    +
    + + + ) +} + +export default StepThree; \ No newline at end of file diff --git a/src/pages/welcome/stepTwo/index.js b/src/pages/welcome/stepTwo/index.js index f40dad3e..e6073fb7 100644 --- a/src/pages/welcome/stepTwo/index.js +++ b/src/pages/welcome/stepTwo/index.js @@ -1,14 +1,39 @@ + import Form from '../../../components/form'; +import NumberInput from '../../../components/form/numberInput'; +import TextInput from '../../../components/form/textInput'; -const StepTwo = ({ data, setData }) => { +const StepTwo = ({ data, setData, formData }) => { return ( <>
    -

    Bio

    +

    Basic info

    - + + +

    *Required

    @@ -16,4 +41,4 @@ const StepTwo = ({ data, setData }) => { ); }; -export default StepTwo; +export default StepTwo; \ No newline at end of file diff --git a/src/pages/welcome/style.css b/src/pages/welcome/style.css index 7ff35605..798591f7 100644 --- a/src/pages/welcome/style.css +++ b/src/pages/welcome/style.css @@ -25,7 +25,7 @@ .welcome-form-inputs { display: grid; grid-template-rows: repeat(auto, auto); - gap: 58px; + gap: 5px; margin-bottom: 48px; } .welcome-form-popup-wrapper { @@ -42,3 +42,35 @@ grid-template-columns: 1fr 1fr; gap: 24px; } + +.welcome-counter { + margin-left: 10px; + font-size: 10px; + color:grey +} + +.bio-label { + font-size: 10px; +} + +.bio-heading { + font-size: 25px; +} + +.addHeadshot { + height: 55px; + color:#64648c; + display: flex; +} + + + +.upload-label { + background-color: var(--color-blue); + color: white; + padding: 14px 24px; + border-radius: 4px; + cursor: pointer; + text-align: center; + font-size: 20px; +} diff --git a/src/service/apiClient.js b/src/service/apiClient.js index 5f3cdbcf..bd58f1e1 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -5,16 +5,23 @@ async function login(email, password) { } async function register(email, password) { - await post('users', { email, password }, false); + await post('signup', { email, password }, false); return await login(email, password); } -async function createProfile(userId, firstName, lastName, githubUrl, bio) { - return await patch(`users/${userId}`, { firstName, lastName, githubUrl, bio }); +async function createProfile(userId, first_name, last_name, username, github_username, mobile, bio, role, specialism, cohort, start_date, end_date, photo) { + console.log(userId, first_name, last_name, username, github_username, mobile, bio, role, specialism, cohort, start_date, end_date, photo) + + cohort = parseInt(cohort) + photo = JSON.stringify(photo) + + await post(`profiles`, { userId, first_name, last_name, username, github_username, mobile, bio, role, specialism, cohort, start_date, end_date, photo }); + return await patch(`users/${userId}`, {}) } async function getPosts() { const res = await get('posts'); + console.log(res.data.posts + " <- this is from apiClient.js"); return res.data.posts; } @@ -49,6 +56,12 @@ async function request(method, endpoint, data, auth = true) { const response = await fetch(`${API_URL}/${endpoint}`, opts); + if (!response.ok) { + const error = new Error(response.message || `Request failed with status ${response.status}`); + error.status = response.status; + throw error; + } + return response.json(); } diff --git a/src/service/mockData.js b/src/service/mockData.js index d49e98a4..6b93d5f8 100644 --- a/src/service/mockData.js +++ b/src/service/mockData.js @@ -5,8 +5,8 @@ const user = { email: 'test@email.com', cohortId: 1, role: 'STUDENT', - firstName: 'Joe', - lastName: 'Bloggs', + first_name: 'Joe', + last_name: 'Bloggs', bio: 'Lorem ipsum dolor sit amet.', githubUrl: 'https://github.com/vherus' } @@ -23,8 +23,8 @@ const posts = [ id: 1, cohortId: 1, role: 'STUDENT', - firstName: 'Sam', - lastName: 'Fletcher', + first_name: 'Sam', + last_name: 'Fletcher', bio: 'Lorem ipsum dolor sit amet.', githubUrl: 'https://github.com/vherus' } @@ -39,8 +39,8 @@ const posts = [ id: 2, cohortId: 1, role: 'STUDENT', - firstName: 'Dolor', - lastName: 'Lobortis', + first_name: 'Dolor', + last_name: 'Lobortis', bio: 'Lorem ipsum dolor sit amet.', githubUrl: 'https://github.com/vherus' },