├── .gitignore
├── .DS_Store
├── client
├── .DS_Store
├── components
│ ├── .DS_Store
│ ├── img
│ │ ├── logo.png
│ │ ├── logo2.png
│ │ ├── Database.png
│ │ └── soundboard-excalidraw.png
│ ├── sounds
│ │ ├── c3.wav
│ │ ├── tom.wav
│ │ ├── .DS_Store
│ │ ├── boom.wav
│ │ ├── clap.wav
│ │ ├── fire.mp3
│ │ ├── geese.wav
│ │ ├── hihat.wav
│ │ ├── kick.mp3
│ │ ├── kick2.wav
│ │ ├── ride.wav
│ │ ├── snare.wav
│ │ ├── tink.wav
│ │ ├── dogbark.wav
│ │ ├── gameover.wav
│ │ ├── openhat.wav
│ │ ├── scratch.mp3
│ │ ├── djairhorn.mp3
│ │ └── sadtrombone.wav
│ ├── App.jsx
│ ├── Button.js
│ ├── Signup.js
│ ├── Board.js
│ └── Login.js
├── index.js
├── test.html
├── index.html
└── index.css
├── postcss.config.js
├── .github
├── workflows
│ ├── proof-html.yml
│ └── auto-assign.yml
└── auto-assign.yml
├── tailwind.config.js
├── server
├── models
│ └── soundboardModel.js
├── controllers
│ ├── soundboardController.js
│ └── loginController.js
├── routes
│ └── api.js
└── server.js
├── package.json
├── README.md
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/.DS_Store
--------------------------------------------------------------------------------
/client/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/.DS_Store
--------------------------------------------------------------------------------
/client/components/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/.DS_Store
--------------------------------------------------------------------------------
/client/components/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/img/logo.png
--------------------------------------------------------------------------------
/client/components/img/logo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/img/logo2.png
--------------------------------------------------------------------------------
/client/components/sounds/c3.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/c3.wav
--------------------------------------------------------------------------------
/client/components/sounds/tom.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/tom.wav
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/client/components/img/Database.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/img/Database.png
--------------------------------------------------------------------------------
/client/components/sounds/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/.DS_Store
--------------------------------------------------------------------------------
/client/components/sounds/boom.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/boom.wav
--------------------------------------------------------------------------------
/client/components/sounds/clap.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/clap.wav
--------------------------------------------------------------------------------
/client/components/sounds/fire.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/fire.mp3
--------------------------------------------------------------------------------
/client/components/sounds/geese.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/geese.wav
--------------------------------------------------------------------------------
/client/components/sounds/hihat.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/hihat.wav
--------------------------------------------------------------------------------
/client/components/sounds/kick.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/kick.mp3
--------------------------------------------------------------------------------
/client/components/sounds/kick2.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/kick2.wav
--------------------------------------------------------------------------------
/client/components/sounds/ride.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/ride.wav
--------------------------------------------------------------------------------
/client/components/sounds/snare.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/snare.wav
--------------------------------------------------------------------------------
/client/components/sounds/tink.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/tink.wav
--------------------------------------------------------------------------------
/client/components/sounds/dogbark.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/dogbark.wav
--------------------------------------------------------------------------------
/client/components/sounds/gameover.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/gameover.wav
--------------------------------------------------------------------------------
/client/components/sounds/openhat.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/openhat.wav
--------------------------------------------------------------------------------
/client/components/sounds/scratch.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/scratch.mp3
--------------------------------------------------------------------------------
/client/components/sounds/djairhorn.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/djairhorn.mp3
--------------------------------------------------------------------------------
/client/components/sounds/sadtrombone.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/sounds/sadtrombone.wav
--------------------------------------------------------------------------------
/client/components/img/soundboard-excalidraw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Red-Laboratories/soundboard/HEAD/client/components/img/soundboard-excalidraw.png
--------------------------------------------------------------------------------
/.github/workflows/proof-html.yml:
--------------------------------------------------------------------------------
1 | name: Proof HTML
2 | on:
3 | push:
4 | workflow_dispatch:
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: anishathalye/proof-html@v1.1.0
10 | with:
11 | directory: ./
12 |
--------------------------------------------------------------------------------
/client/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import App from './components/App.jsx'
4 | import './index.css';
5 |
6 |
7 | const container = document.getElementById('root')
8 | const root = createRoot(container);
9 | root.render(
10 |
11 | );
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./client/**/*.{html,js,jsx,ts,tsx}",
5 | ],
6 | theme: {
7 | extend: {
8 | padding: {
9 | '1/2': '50%',
10 | full: '100%',
11 | },
12 | },
13 | },
14 | plugins: [],
15 | }
16 |
--------------------------------------------------------------------------------
/client/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 | Test route
11 |
12 |
--------------------------------------------------------------------------------
/.github/workflows/auto-assign.yml:
--------------------------------------------------------------------------------
1 | name: Auto Assign
2 | on:
3 | issues:
4 | types: [opened]
5 | pull_request:
6 | types: [opened]
7 | jobs:
8 | run:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: wow-actions/auto-assign@v1
12 | with:
13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 | CONFIG_FILE: .github/auto-assign.yml
15 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Soundboard
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/server/models/soundboardModel.js:
--------------------------------------------------------------------------------
1 | const { Pool } = require('pg');
2 |
3 | const PG_URI = 'postgres://todkkube:CvOHogNm7N1EuKBBFbei6muuGH_Uq160@heffalump.db.elephantsql.com/todkkube';
4 |
5 | const pool = new Pool ({
6 | connectionString: PG_URI
7 | });
8 |
9 |
10 | module.exports = {
11 | query: (text, params, callback) => {
12 | console.log('Executed query', text);
13 | return pool.query(text, params, callback);
14 | }
15 | };
--------------------------------------------------------------------------------
/client/index.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@100;400;500;600;700&display=swap);
2 |
3 | *{
4 | margin: 0;
5 | padding: 2.5%;
6 | box-sizing: border-box;
7 | }
8 |
9 | body{
10 | font-family: 'Josefin+Sans', sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
11 | }
12 |
13 | html,
14 | body{
15 | scroll-behavior: smooth;
16 | }
17 |
18 | @tailwind base;
19 | @tailwind components;
20 | @tailwind utilities;
--------------------------------------------------------------------------------
/client/components/App.jsx:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import {BrowserRouter, Routes, Route} from 'react-router-dom';
3 |
4 | import Login from './Login';
5 | import Board from './Board';
6 | import Signup from './Signup';
7 |
8 |
9 | function App() {
10 | return (
11 |
12 |
13 | } />
14 | } />
15 | } />
16 |
17 |
18 | )
19 |
20 | }
21 |
22 | export default App;
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.github/auto-assign.yml:
--------------------------------------------------------------------------------
1 | # Set to true to add reviewers to PRs
2 | addReviewers: true
3 |
4 | # Set to 'author' to add PR's author as a assignee
5 | addAssignees: author
6 |
7 | # A list of reviewers to be added to PRs (GitHub user name)
8 | reviewers:
9 | - omahomie1
10 |
11 | # A number of reviewers added to the PR
12 | # Set 0 to add all the reviewers (default: 0)
13 | numberOfReviewers: 1
14 |
15 | # A list of assignees, overrides reviewers if set
16 | assignees:
17 | - omahomie1
18 |
19 | # A number of assignees to add to the PRs
20 | # Set to 0 to add all of the assignees.
21 | # Uses numberOfReviewers if unset.
22 | numberOfAssignees: 0
23 |
24 | # A list of keywords to be skipped the process if PR's title include it
25 | skipKeywords:
26 | - wip
27 |
--------------------------------------------------------------------------------
/client/components/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Howl, Howler } from 'howler';
3 |
4 | function Button(props) {
5 | const logKey = (e) => {
6 | console.log(e.keyCode)
7 | }
8 |
9 | // const playSound = (e) => {
10 | // const audio = document.getElementById(`${e.keyCode}`);
11 | // if (!audio) return;
12 |
13 | // audio.click();s
14 | // }
15 |
16 | // window.addEventListener('keydown', playSound);
17 |
18 | const sound = require(`./sounds/${props.sound}`).default;
19 |
20 | const clickSound = (src) => {
21 | const sound = new Howl({
22 | src
23 | });
24 | // sound.currentTime = 0;
25 | sound.play();
26 | }
27 |
28 | Howler.volume(0.5);
29 | return (
30 | clickSound(sound)} id={props.btnKey.charCodeAt(0)} className="w-full h-0 pb-full bg-slate-300 text-black hover:bg-slate-200 shadow-2xl py-2 px-4 border-b-8 border-slate-500 transition-all ease-in-out rounded-xl cursor-pointer border">
31 | {props.btnKey}
32 |
33 | ...
34 |
35 |
36 | )
37 | }
38 |
39 |
40 | export default Button;
--------------------------------------------------------------------------------
/server/controllers/soundboardController.js:
--------------------------------------------------------------------------------
1 | const db = require('../models/soundboardModel');
2 |
3 | const soundboardController = {};
4 |
5 | const createErr = (method) => {
6 | return ({
7 | log: `This error occured in ${method} method inside soundboardController`,
8 | message: `This error occured in ${method} method inside soundboardController, check terminal for error info`
9 | });
10 | };
11 |
12 | soundboardController.getButtons = (req, res, next) => {
13 | const buttonStr = 'SELECT button_components.*, sounds.sound FROM button_components LEFT JOIN sounds ON button_components.sound_id = sounds.id'
14 | db.query(buttonStr)
15 | .then(data => {
16 | res.locals.buttons = data.rows;
17 | return next();
18 | })
19 | .catch(e => {
20 | return next(createErr('getButtons'));
21 | })
22 | }
23 |
24 |
25 | soundboardController.getSounds = (req, res, next) => {
26 | const query = 'SELECT * FROM sounds'
27 | db
28 | .query(query)
29 | .then(data => {
30 | const arrOfSounds = [];
31 | for (let i = 0; i < data.rows.length; i++) {
32 | arrOfSounds.push(data.rows[i].sound)
33 | }
34 | res.locals.sounds = arrOfSounds;
35 | return next();
36 | })
37 | .catch(e => {
38 | return next(createErr('getButtons'));
39 | })
40 | }
41 |
42 |
43 | module.exports = soundboardController;
44 |
--------------------------------------------------------------------------------
/server/routes/api.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const soundboardController = require('../controllers/soundboardController');
3 | const loginController = require('../controllers/loginController');
4 | const router = express.Router();
5 |
6 |
7 | router.get('/main',
8 | loginController.checkCookies,
9 | soundboardController.getButtons,
10 | (req, res) => res.status(200).json(res.locals.buttons));
11 |
12 |
13 | // main page
14 | // app.get('/', (req, res) => {
15 | // return res.status(200).sendFile(path.join(__dirname, '../client/index.html'))
16 | // })
17 |
18 | router.post('/login',
19 | loginController.checkCredentials,
20 | loginController.setCookie,
21 | (req, res) => res.status(200).json({}));
22 |
23 | router.delete('/logout',
24 | loginController.logout,
25 | (req, res) => res.status(200).json('success'));
26 |
27 |
28 | // router.get('/main',
29 | // loginController.checkCookie,
30 | // (req, res) => res.status(200).json({}));
31 |
32 |
33 | // router.post('/signup', (req, res) => res.status(200).json({}));
34 |
35 | // router.get('/login', (req, res) => res.status(200).json({}));
36 |
37 |
38 |
39 | // router.get('/login', (req, res) => res.status(200).json({}));
40 |
41 | // router.patch('/main', (req, res) => res.status(200).json({}));
42 |
43 | router.get('/sounds', soundboardController.getSounds, (req, res) => res.status(200).json(res.locals.sounds));
44 |
45 | module.exports = router;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo-repo",
3 | "version": "0.2.0",
4 | "description": "A sample package.json",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "export NODE_ENV=production; nodemon server/server.js",
8 | "build": "export NODE_ENV=production; webpack",
9 | "dev": "export NODE_ENV=development; webpack-dev-server --open & nodemon server/server.js"
10 | },
11 | "dependencies": {
12 | "@babel/core": "^7.19.3",
13 | "@babel/plugin-proposal-class-properties": "^7.18.6",
14 | "@babel/preset-env": "^7.19.3",
15 | "@babel/preset-react": "^7.18.6",
16 | "@primer/css": "17.0.1",
17 | "babel-loader": "^8.2.5",
18 | "cookie-parser": "^1.4.6",
19 | "css-loader": "^6.7.1",
20 | "express": "^4.18.1",
21 | "file-loader": "^6.2.0",
22 | "howler": "^2.2.3",
23 | "html-webpack-plugin": "^5.5.0",
24 | "node-sass": "^7.0.3",
25 | "nodemon": "^2.0.20",
26 | "pg": "^8.8.0",
27 | "postcss-loader": "^7.0.1",
28 | "postcss-preset-env": "^7.8.2",
29 | "react": "^18.2.0",
30 | "react-dom": "^18.2.0",
31 | "react-router": "^6.4.1",
32 | "react-router-dom": "^6.4.1",
33 | "sass-loader": "^13.0.2",
34 | "style-loader": "^3.3.1",
35 | "styles-loader": "^4.0.1",
36 | "webpack": "^5.74.0",
37 | "webpack-cli": "^4.10.0",
38 | "webpack-dev-server": "^4.11.1"
39 | },
40 | "license": "MIT",
41 | "devDependencies": {
42 | "autoprefixer": "^10.4.12",
43 | "postcss": "^8.4.17",
44 | "tailwindcss": "^3.1.8"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DJ SoundBoard
2 | Online launchpad that allows you to customize a grid of buttons and play them using your keyboard
3 |
4 | ## Overview
5 |
6 | ### Techstack
7 | 1. React
8 | 2. React Router
9 | 3. Howler - audio library
10 | 4. SQL
11 | 5. Express
12 | 6. Node
13 | 7. Tailwind - styling
14 |
15 | ### Diagrams
16 | * Importable Scene to [Excalidraw](./client/components/img/soundboard-excalidraw.png)
17 | -Contains mapping of frontend and backend
18 | * [ER Diagram](./client/components/img/Database.png)
19 |
20 | ### Setup
21 | 1. Execute npm install
22 | 2. devServer - use npm run dev
23 | 3. production - **sounds currently not working**
24 | 1. npm run build
25 | 2. npm start
26 | 4. Login
27 | * At server startup you will be auto directed to a login page. Please enter the below credentials to use the sound board
28 | * Username: tracy
29 | * Password: ilovedogs
30 |
31 | ### Working features
32 | 1. Login/Logout
33 | 2. Cookies and Sessions
34 | *unable to bypass login screen without correct credentials
35 | 3. playing sounds via mouse click and/or keyboard
36 | 4. Database storing button keyboard value and sound file name
37 |
38 | ### Notes
39 | 1. Sounds currently not playing while in production
40 | 1. You may want to change the URI for the SQL database for better configuring.
41 | [URI Location](server/models/soundboardModel.js)
42 | 2. Importing new sounds -
43 | 1. Download sounds to your local machine first
44 | 2. Test sounds using your preferred media player
45 | 3. Drag and drop into [sound](client/components/sounds)
46 | 3. Keyboard values on board are supposed to be in the following order for better UX, but order got rearranged working on an imcomplete feature.
47 | * Q W E
48 | * A S D
49 | * Z X C
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HTMLWebPackPlugin = require('html-webpack-plugin');
3 | const environment = process.env.Node_ENV;
4 |
5 | module.exports = {
6 | // add mode
7 | mode: environment,
8 | // define entry point
9 | entry: './client/index.js',
10 | // define output
11 | output: {
12 | path: path.resolve(__dirname, './build'),
13 | filename: 'bundle.js',
14 | publicPath: '/'
15 | },
16 | // add plugin(s) html webpack
17 | plugins: [
18 | new HTMLWebPackPlugin({
19 | template: './client/index.html'
20 | })
21 | ],
22 |
23 | // add rules with all necessary loader and presets
24 | module: {
25 | rules: [
26 | {
27 | test: /\.(js|jsx)$/,
28 | exclude: /node_modules/,
29 | use: {
30 | loader: 'babel-loader',
31 | options: {
32 | presets: ['@babel/preset-env', '@babel/preset-react']
33 | }
34 | }
35 | },
36 | {
37 | test: /\.css$/i,
38 | use: ['style-loader', 'css-loader', 'postcss-loader'],
39 | },
40 | {
41 | test: /\.png|svg|jpg|gif$/,
42 | use: [
43 | {
44 | loader: 'file-loader',
45 | options: {
46 | name: '[name].[ext]'
47 | }
48 | }
49 | ]
50 | },
51 | {
52 | test: /\.(wav|mp3)$/,
53 | use: [
54 | {
55 | loader: 'file-loader',
56 | options: {
57 | name: '[name].[ext]'
58 | }
59 | }
60 | ]
61 | },
62 | ],
63 | },
64 |
65 | // set up dev server
66 | devServer: {
67 | static: {
68 | directory: path.join(__dirname, './build'), // path.resolve => user/tommyli/desktop/scractchproject/soundboard/build
69 | },
70 | historyApiFallback: true,
71 | // set up proxy
72 | compress: true,
73 | port: 8080,
74 | hot: true,
75 | proxy: {
76 | '/api': 'http://localhost:3000' // localhost:3000/
77 | }
78 | }
79 |
80 | };
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const path = require('path');
4 | const apiRouter = require('./routes/api');
5 | const cookieParser = require('cookie-parser');
6 |
7 | app.use(express.json());
8 | app.use(express.urlencoded({ extended: true }));
9 | app.use(cookieParser());
10 |
11 | // send to api router for requests to database
12 | app.use('/api', apiRouter);
13 |
14 | // must keep express.static to serve bundle.js
15 | app.use('/build', express.static(path.join(__dirname, "../build")));
16 |
17 | app.get('/', (req, res) => {
18 | console.log('we should see this ');
19 | return res.status(200).sendFile(path.join(__dirname, '../client/index.html'))
20 | })
21 |
22 |
23 |
24 | app.get('/*', (req, res) => {
25 | return res.status(200).sendFile(path.join(__dirname, '../client/index.html'));
26 | });
27 |
28 |
29 | // local error handler
30 | app.use((req, res) => {
31 | // server log
32 | console.log('this endpoint does not exist in server.js');
33 | // response to client
34 | res.status(404).send('this page does not exist');
35 | })
36 |
37 | // global error handler
38 | app.use((err, req, res, next) => {
39 | // create default error object
40 | let defaultErr = {
41 | log: 'there is an error with unspecified middleware',
42 | status: 500,
43 | message: { err: 'there is a server side error' }
44 | }
45 | // reassign default error object with info passed in via err arg
46 | defaultErr = Object.assign(defaultErr, err);
47 | // log server side error to server terminal
48 | console.log(defaultErr.log);
49 | // return status and client side error to client
50 | res.status(defaultErr.status).send(defaultErr.message);
51 | });
52 |
53 |
54 |
55 |
56 | app.listen(3000, () => {
57 | console.log('Server listening on Port 3000')
58 | });
59 |
60 | // module.exports = app;
--------------------------------------------------------------------------------
/client/components/Signup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import login from './img/logo.png'
3 |
4 | function Signup () {
5 | return(
6 | //
7 | //
8 | //
9 | //
10 | //
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | )
39 | }
40 |
41 |
42 | export default Signup;
--------------------------------------------------------------------------------
/client/components/Board.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import Button from './Button';
3 | import logo2 from './img/logo2.png'
4 |
5 |
6 | // make get request to server to verify if there is cookie first
7 | const checkCookie = () => {
8 | // make get request to which endpoint?
9 | fetch('/api/main')
10 | .then(res => res.json())
11 | .then(data => {
12 | if (data === 'unauthorized') {
13 | // re-route request to home page if they do not have a cookie
14 | window.location.href = '/';
15 | } else {
16 | console.log('welcome back!')
17 | }
18 | })
19 | .catch(err =>console.log('error with checkCookie in Board.js'))
20 | };
21 |
22 | // create a logout function
23 | const logout = () => {
24 | fetch('/api/logout', {
25 | method: 'DELETE'
26 | })
27 | .then(res => res.json())
28 | .then(data => {
29 | // reroute to login page after deleting cookie
30 | window.location.href = '/';
31 | })
32 | .catch(err =>console.log('error with logout in Board.js'))
33 | };
34 |
35 |
36 |
37 | function Board() {
38 | checkCookie();
39 | const playSound = (e) => {
40 | const audio = document.getElementById(`${e.keyCode}`);
41 | if (!audio) return;
42 |
43 | audio.click();
44 | }
45 |
46 | window.addEventListener('keydown', playSound);
47 |
48 | const [state, changeState] = useState();
49 |
50 | useEffect(() => {
51 | fetch('/api/main')
52 | .then(res => res.json())
53 | .then(data => {
54 | console.log(data)
55 | changeState(data)
56 | })
57 | .catch(err => console.log(err))
58 | }, [])
59 |
60 | if (!state) {
61 | return <>>
62 | }
63 |
64 | const board = []
65 | for (let i = 0; i < 9; i++) {
66 | board.push()
67 | }
68 |
69 | return (
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {board}
79 | {/* {renderButtons()} */}
80 |
81 |
82 |
83 | )
84 | }
85 |
86 | export default Board;
87 |
--------------------------------------------------------------------------------
/server/controllers/loginController.js:
--------------------------------------------------------------------------------
1 | const db = require('../models/soundboardModel');
2 |
3 | const loginController = {};
4 |
5 | const createErr = (method) => {
6 | return ({
7 | log: `This error occured in ${method} method inside loginController`,
8 | message: `This error occured in ${method} method inside loginController, check terminal for error info`
9 | });
10 | };
11 |
12 |
13 | loginController.checkCredentials = (req, res, next) => {
14 | // get credentials from req.body and destructure them
15 | const { username, password:pw } = req.body;
16 | // console.log(pw)
17 | // create a query
18 | const query = 'SELECT * FROM person WHERE username = $1 AND password = $2;';
19 | // query databse to see if that username and password exists
20 | db.query(query, [username, pw])
21 | .then(dbResponse => {
22 | if (dbResponse.rows[0] === undefined) {
23 | // if file is not returned
24 | return res.status(401).json('failed login');
25 | } else {
26 | // if a file is returned next
27 | const { username, id } = dbResponse.rows[0];
28 | // console.log(username, id)
29 | res.locals.user = {
30 | 'username': username,
31 | 'user_id': id
32 | };
33 | return next()
34 | }
35 | })
36 | // err handling
37 | .catch(err => next(createErr(err)));
38 | };
39 |
40 | loginController.setCookie = (req, res, next) => {
41 | // add current user to sessions table in database
42 | const { user_id, username } = res.locals.user;
43 | const session_id = Math.random().toString();
44 | // creates cookie
45 | res.cookie('SSID', session_id);//add optionality to cookie?
46 |
47 | // add cookie and user to sessions table in db
48 | const add = 'INSERT INTO sessions (session, user_id) VALUES ($1, $2);'
49 | db.query(add, [session_id, user_id])
50 | .then(res => {
51 | // console.log(res)
52 | return next();
53 | })
54 | .catch(err => next(createErr(err)));
55 | };
56 |
57 | // req.cookies: { tracy: '0.023381441699068528' },
58 | // req.cookies: { SSID: '0.023381441699068528' },
59 |
60 | loginController.checkCookies = (req, res, next) => {
61 | // check if there is a current cookie
62 | const checkCookie = 'SELECT * FROM sessions WHERE $1 = session;';
63 | db.query(checkCookie, [req.cookies.SSID]) //
64 | .then(dbRes => {
65 | // console.log('dbRes: ',dbRes.rows[0]);
66 | //if there is no response, redirect
67 | if (dbRes.rows[0] === undefined) {
68 | res.status(401).json('unauthorized');
69 | }
70 | // if there is a response, proceed
71 | return next();
72 | })
73 | .catch(err => { next(createErr(err)) });
74 | }
75 |
76 | loginController.logout = (req, res, next) => {
77 | // delete cookie in databse
78 | const deleteCookie = 'DELETE FROM sessions WHERE $1 = session;';
79 | db.query(deleteCookie, [req.cookies.SSID]) //
80 | .then(dbRes => {
81 | console.log('dbRes: ',dbRes.rows[0]);
82 | return next();
83 | })
84 | .catch(err => { next(createErr(err)) });
85 | }
86 |
87 |
88 | module.exports = loginController;
--------------------------------------------------------------------------------
/client/components/Login.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import login from './img/logo.png'
3 |
4 | function loginClick() {
5 | const username = document.getElementById('username').value;
6 | const password = document.getElementById('password').value;
7 | console.log(username, password);
8 | if (!username) alert('Need to enter a username!');
9 | if (!password) alert('Need to enter a password!');
10 | // make post request to server with username and password
11 | fetch('api/login', {
12 | method: 'POST',
13 | body: JSON.stringify({
14 | username,
15 | password
16 | }),
17 | headers: {
18 | 'Content-type': 'application/json'
19 | }
20 | })
21 | .then(res => res.json())
22 | .then(data => {
23 | if (data === 'failed login') {
24 | // send alert if login attemp failed
25 | alert('you have entered an incorrect username/password')
26 | } else {
27 | // if verified redirect to homepage
28 | window.location.href = '/board'
29 | }
30 | })
31 | .catch(err => console.log('Login error: ', err));
32 | }
33 |
34 | function Login () {
35 | return(
36 | //
37 | //
38 | //
39 | //
40 | //
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
62 |
63 |
64 |
65 |
68 |
69 |
70 |
71 | )
72 | }
73 |
74 |
75 | export default Login;
76 |
--------------------------------------------------------------------------------