Repository: bradtraversy/codegig Branch: master Commit: 8e8f43cfb3f3 Files: 14 Total size: 13.5 KB Directory structure: gitextract_0ajwmxgi/ ├── .gitignore ├── README.md ├── app.js ├── config/ │ └── database.js ├── models/ │ └── Gig.js ├── package.json ├── public/ │ └── css/ │ └── style.css ├── routes/ │ └── gigs.js └── views/ ├── add.handlebars ├── error.handlebars ├── gigs.handlebars ├── index.handlebars └── layouts/ ├── landing.handlebars └── main.handlebars ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ node_modules .env ================================================ FILE: README.md ================================================ # CodeGig > Simple Job find app for coders. This app uses Node, Express, Sequalize (Postgres) and Handlebars. ## Quick Start ``` bash # Install dependencies npm install # Serve on localhost:5000 npm start # Dev Server (Nodemon) npm run dev ``` ## App Info ### Author Brad Traversy [Traversy Media](http://www.traversymedia.com) ### Version 1.0.0 ### License This project is licensed under the MIT License ================================================ FILE: app.js ================================================ const express = require('express'); const exphbs = require('express-handlebars'); const bodyParser = require('body-parser'); const path = require('path'); // Database const db = require('./config/database'); // Test DB db.authenticate() .then(() => console.log('Database connected...')) .catch(err => console.log('Error: ' + err)) const app = express(); // Handlebars app.engine('handlebars', exphbs({ defaultLayout: 'main' })); app.set('view engine', 'handlebars'); // Body Parser app.use(express.urlencoded({ extended: false })); // Set static folder app.use(express.static(path.join(__dirname, 'public'))); // Index route app.get('/', (req, res) => res.render('index', { layout: 'landing' })); // Gig routes app.use('/gigs', require('./routes/gigs')); const PORT = process.env.PORT || 5000; app.listen(PORT, console.log(`Server started on port ${PORT}`)); ================================================ FILE: config/database.js ================================================ const Sequelize = require('sequelize'); const dotenv = require('dotenv'); dotenv.config(); module.exports = new Sequelize(process.env.DATABASE_URL, { host: 'localhost', dialect: 'postgres', operatorsAliases: false, pool: { max: 5, min: 0, acquire: 30000, idle: 10000 }, }); ================================================ FILE: models/Gig.js ================================================ const Sequelize = require('sequelize'); const db = require('../config/database'); const Gig = db.define('gig', { title: { type: Sequelize.STRING }, technologies: { type: Sequelize.STRING }, description: { type: Sequelize.STRING }, budget: { type: Sequelize.STRING }, contact_email: { type: Sequelize.STRING } }); Gig.sync().then(() => { console.log('table created'); }); module.exports = Gig; ================================================ FILE: package.json ================================================ { "name": "codegig", "version": "1.0.0", "description": "Simple job find app for coders", "main": "app.js", "scripts": { "start": "node app.js", "dev": "nodemon app.js" }, "author": "Brad Traversy", "license": "MIT", "dependencies": { "dotenv": "^8.1.0", "express": "^4.16.4", "express-handlebars": "^3.0.0", "pg": "^7.7.1", "pg-hstore": "^2.3.2", "sequelize": "^4.44.3" }, "devDependencies": { "nodemon": "^1.18.8" } } ================================================ FILE: public/css/style.css ================================================ @import url('https://fonts.googleapis.com/css?family=Lato'); :root { --primary-color: #568c9b; --primary-hover-color: #64a5b7; --bg-color: #333; --box-shadow: 3px 4px 12px rgba(0, 0, 0, 0.7); } * { box-sizing: border-box; } body { font-family: 'Lato', sans-serif; margin: 0; color: #333; background: #f4f4f4; } ul { list-style: none; padding: 0; } a { color: #fff; text-decoration: none; } a:hover { color: var(--primary-color); } .container { max-width: 960px; padding: 1rem 4rem; margin: auto; overflow: hidden; } .error { padding: 5px; border: #777 dotted 1px; margin-bottom: 15px; } /* Header */ header { display: flex; position: absolute; top: 0; left: 0; width: 100%; justify-content: space-between; align-items: center; padding: 1rem 6rem; } header nav ul { display: flex; } header nav li { margin: 0 1rem; } /* Login Button Spacing */ /*header nav li:last-child { margin-left: -5px; }*/ header.inner { background: var(--bg-color); border-bottom: 4px solid var(--primary-color); position: relative; box-shadow: var(--box-shadow); } /* Buttons */ .btn { color: #fff; padding: 0.6rem; border: 1px solid #ccc; transition: all 0.7s; } .btn:hover { background: var(--primary-color); border: 1px solid var(--primary-color); color: #fff; } .btn-reverse { background: var(--primary-color); border: 1px solid var(--primary-color); } .btn-reverse:hover { background: var(--primary-hover-color); border: 1px solid var(--primary-hover-color); } /* Home Search */ .search-wrap { background: url('../img/showcase.jpg') no-repeat center center fixed; background-size: cover; height: 100vh; width: 100%; padding: 1.3rem 3rem; display: flex; flex-direction: column; justify-content: center; align-items: center; } .search-wrap h1 { font-size: 3rem; font-weight: 800; color: #fff; margin: 0 0 1.5rem; text-align: center; } .search-form input[type='submit'] { background: var(--primary-color); border: 1px solid var(--primary-color); color: #fff; padding: 0 2rem; cursor: pointer; transition: all 0.8s; } .search-form input[type='submit']:hover { background: var(--primary-hover-color); border: 1px solid var(--primary-hover-color); } .search-form { display: flex; width: 600px; box-shadow: var(--box-shadow); } .search-form i { color: #333; } /* Everything in the search form */ .search-form > * { border: 0; padding: 0 0 0 10px; background: #fff; line-height: 50px; font-size: 1rem; border-radius: 0; outline: 0; } input[type='search'] { flex-basis: 600px; } /* Gigs */ .gig { background: var(--bg-color); border-bottom: 4px solid var(--primary-color); color: #fff; padding: 1rem; margin-bottom: 1rem; box-shadow: var(--box-shadow); } .gig ul { list-style: none; display: flex; } .gig li { margin-right: 0.5rem; padding: 0.6rem; } .gig .tech span { color: var(--primary-color); } /* Form */ .form-wrap { margin: auto; background: var(--bg-color); color: #fff; padding: 1rem 3rem 3rem; margin-top: 3rem; border-bottom: 4px solid var(--primary-color); box-shadow: var(--box-shadow); } .form-wrap.reg-form, .form-wrap.login-form { width: 60%; } .form-wrap h1, .form-wrap h2, .form-wrap p { text-align: center; } .form-wrap .btn { margin-top: 1rem; display: block; width: 100%; text-align: center; font-size: 18px; } label { display: block; margin-bottom: 0.5rem; } .input-box { padding: 0.5rem; font-size: 18px; width: 100%; margin-bottom: 1.2rem; } /* Tablets */ @media (max-width: 800px) { .container { padding: 1rem 2rem; } header { flex-direction: column; padding: 0.3rem !important; } .search-form { width: 100%; } input[type='search'] { flex-basis: 100%; } .search-wrap h1 { font-size: 2rem; } .search-wrap { padding: 2.3rem; } .gig ul { flex-direction: column; } .gig .btn { display: block; margin-top: 1rem; text-align: center; } .form-wrap.reg-form, .form-wrap.login-form { width: 80%; } } /* Smartphones */ @media (max-width: 500px) { .container { padding: 1rem; } header nav li { margin: 0 10px; } .search-form { display: flex; flex-direction: column; } input[type='search'] { flex-basis: 0; } .search-form i { display: none; } .form-wrap { padding: 1rem 2rem 2rem; } .form-wrap.reg-form, .form-wrap.login-form { width: 100%; } } ================================================ FILE: routes/gigs.js ================================================ const express = require('express'); const router = express.Router(); const db = require('../config/database'); const Gig = require('../models/Gig'); const Sequelize = require('sequelize'); const Op = Sequelize.Op; // Get gig list router.get('/', (req, res) => Gig.findAll() .then(gigs => res.render('gigs', { gigs })) .catch(err => res.render('error', {error: err}))); // Display add gig form router.get('/add', (req, res) => res.render('add')); // Add a gig router.post('/add', (req, res) => { let { title, technologies, budget, description, contact_email } = req.body; let errors = []; // Validate Fields if(!title) { errors.push({ text: 'Please add a title' }); } if(!technologies) { errors.push({ text: 'Please add some technologies' }); } if(!description) { errors.push({ text: 'Please add a description' }); } if(!contact_email) { errors.push({ text: 'Please add a contact email' }); } // Check for errors if(errors.length > 0) { res.render('add', { errors, title, technologies, budget, description, contact_email }); } else { if(!budget) { budget = 'Unknown'; } else { budget = `$${budget}`; } // Make lowercase and remove space after comma technologies = technologies.toLowerCase().replace(/,[ ]+/g, ','); // Insert into table Gig.create({ title, technologies, description, budget, contact_email }) .then(gig => res.redirect('/gigs')) .catch(err => res.render('error', {error:err.message})) } }); // Search for gigs router.get('/search', (req, res) => { let { term } = req.query; // Make lowercase term = term.toLowerCase(); Gig.findAll({ where: { technologies: { [Op.like]: '%' + term + '%' } } }) .then(gigs => res.render('gigs', { gigs })) .catch(err => res.render('error', {error: err})); }); module.exports = router; ================================================ FILE: views/add.handlebars ================================================

Add A Gig

Your contact email will be shared with registered users to apply to your gig

{{#each errors}}

{{text}}

{{/each}}
================================================ FILE: views/error.handlebars ================================================

An error occured



{{error}}

================================================ FILE: views/gigs.handlebars ================================================

All Gigs

{{#each gigs}}

{{title}}

{{description}}

Technologies Needed: {{technologies}}
{{else}}

No gigs available

{{/each}}
================================================ FILE: views/index.handlebars ================================================ ================================================ FILE: views/layouts/landing.handlebars ================================================ CodeGig

CodeGig

{{{body}}} ================================================ FILE: views/layouts/main.handlebars ================================================ CodeGig

CodeGig

{{{body}}}