Skip to content

Commit

Permalink
Init 2
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy Leverenz committed Nov 20, 2018
1 parent 045c133 commit 499ad85
Show file tree
Hide file tree
Showing 67 changed files with 1,134 additions and 19 deletions.
8 changes: 7 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

Expand Down Expand Up @@ -67,6 +67,12 @@ gem 'foreman', '~> 0.84.0'
gem 'sidekiq', '~> 5.1', '>= 5.1.3'
gem 'tailwindcss', '~> 0.2.0'
gem 'webpacker', '~> 3.5', '>= 3.5.3'

# consultly specific
gem 'simple_calendar', '~> 2.3'
gem 'trix', '~> 0.9.9'
gem 'stripe', '~> 4.0', '>= 4.0.2'

group :development, :test do
gem 'better_errors'
end
16 changes: 16 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ GEM
warden (~> 1.2.3)
erubi (1.7.1)
execjs (2.7.0)
faraday (0.15.3)
multipart-post (>= 1.2, < 3)
ffi (1.9.25)
foreman (0.84.0)
thor (~> 0.19.1)
Expand Down Expand Up @@ -120,6 +122,9 @@ GEM
minitest (5.11.3)
msgpack (1.2.4)
multi_json (1.13.1)
multipart-post (2.0.0)
net-http-persistent (3.0.0)
connection_pool (~> 2.2)
nio4r (2.3.1)
nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
Expand Down Expand Up @@ -186,6 +191,8 @@ GEM
connection_pool (~> 2.2, >= 2.2.2)
rack-protection (>= 1.5.0)
redis (>= 3.3.5, < 5)
simple_calendar (2.3.0)
rails (>= 3.0)
spring (2.0.2)
activesupport (>= 4.2)
spring-watcher-listen (2.0.1)
Expand All @@ -199,11 +206,16 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.3.13)
stripe (4.0.3)
faraday (~> 0.13)
net-http-persistent (~> 3.0)
tailwindcss (0.2.0)
railties (>= 4.1.0, < 6.0)
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.8)
trix (0.9.10)
rails
turbolinks (5.2.0)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
Expand Down Expand Up @@ -245,13 +257,17 @@ DEPENDENCIES
listen (>= 3.0.5, < 3.2)
puma (~> 3.11)
rails (~> 5.2.1)
redis (~> 4.0)
sass-rails (~> 5.0)
selenium-webdriver
sidekiq (~> 5.1, >= 5.1.3)
simple_calendar (~> 2.3)
spring
spring-watcher-listen (~> 2.0.0)
sqlite3
stripe (~> 4.0, >= 4.0.2)
tailwindcss (~> 0.2.0)
trix (~> 0.9.9)
turbolinks (~> 5)
tzinfo-data
uglifier (>= 1.3.0)
Expand Down
1 change: 1 addition & 0 deletions app/assets/images/move-forward.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/images/schedule.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/images/teacher.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
//
//= require rails-ujs
//= require activestorage
//= require trix
//= require turbolinks
//= require_tree .
Empty file.
29 changes: 29 additions & 0 deletions app/assets/javascripts/meetings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
document.addEventListener("turbolinks:load", () => {
const tabElements = document.querySelectorAll('#nav-tab .tab');

function onTabClick(event) {
const activeTabs = document.querySelectorAll('.active');

activeTabs.forEach(function(tab) {
tab.classList.toggle('active');
});


event.target.parentElement.classList.add('active');

event.preventDefault();

// show and hide tab panels
var tabPanel = document.getElementById(event.target.href.split("#")[1]);
tabPanel.classList.toggle('active');
}


if(tabElements != null) {
tabElements.forEach(function(tab) {
tab.addEventListener('click', (event) => {
onTabClick(event);
});
});
}
});
81 changes: 81 additions & 0 deletions app/assets/javascripts/purchases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
document.addEventListener("turbolinks:load", function() {
const public_key = document.querySelector("meta[name='stripe-public-key']").content;
const stripe = Stripe(public_key);
const elements = stripe.elements();

const style = {
base: {
color: '#32325d',
lineHeight: '26px',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
const cardElement = document.getElementById('card-element');

if(cardElement != null) {

const card = elements.create('card', {style: style});
card.mount(cardElement);

card.addEventListener('change', ({error}) => {
const displayError = document.getElementById('card-errors');
if (error) {
displayError.textContent = error.message;
} else {
displayError.textContent = '';
}
});


const form = document.querySelector('.meeting-form');
form.addEventListener('submit', async (event) => {
event.preventDefault();

const {token, error} = await stripe.createToken(card);

if (error) {
// Inform the customer that there was an error.
const errorElement = document.getElementById('card-errors');
errorElement.textContent = error.message;
} else {
// Send the token to your server.
stripeTokenHandler(token);
}
});

const stripeTokenHandler = (token) => {
// Insert the token ID into the form so it gets submitted to the server
const form = document.querySelector('.meeting-form');
const hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);

["brand", "exp_month", "exp_year", "last4"].forEach(function(field) {
addFieldToForm(form, token, field);
});

// Submit the form
form.submit();
}

function addFieldToForm(form, token, field) {
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', "user[card_" + field + "]");
hiddenInput.setAttribute('value', token.card[field]);
form.appendChild(hiddenInput);
}
}

});
5 changes: 5 additions & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
*= require simple_calendar
*= require trix
*= require_tree .
*/
6 changes: 6 additions & 0 deletions app/assets/stylesheets/calendar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.simple-calendar {
.prev-month,
.next-month {
background: #efefef;
}
}
3 changes: 3 additions & 0 deletions app/assets/stylesheets/comments.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the comments controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
3 changes: 3 additions & 0 deletions app/assets/stylesheets/meetings.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the Meetings controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
45 changes: 45 additions & 0 deletions app/controllers/comments_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class CommentsController < ApplicationController
before_action :authenticate_user! # authenticate before anyone can comment who is not logged in.
before_action :set_comment, only: [:edit, :update, :show, :destroy]
before_action :set_meeting

def new
@comment = Comment.new
end

def create
@comment = @meeting.comments.create(params[:comment].permit(:reply, :meeting_id))
@comment.user_id = current_user.id

respond_to do |format|
if @comment.save
format.html { redirect_to meeting_path(@meeting) }
format.js # renders create.js.erb
else
format.html { redirect_to meeting_path(@meeting), notice: "Your comment did not save. Please try again." }
format.js
end
end
end

def destroy
@comment = @meeting.comments.find(params[:id])
@comment.destroy
redirect_to meeting_path(@meeting)
end

private

def set_meeting
@meeting = Meeting.find(params[:meeting_id])
end

def set_comment
@comment = Comment.find(params[:id])
end

def comment_params
params.require(:comment).permit(:reply)
end

end
117 changes: 117 additions & 0 deletions app/controllers/meetings_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
class MeetingsController < ApplicationController
before_action :authenticate_user!
before_action :set_meeting, only: [:show, :edit, :update, :destroy]
before_action :must_be_admin, only: [:active_sessions]

# GET /meetings
# GET /meetings.json
def index
if current_user.admin?
@meetings = Meeting.all
else
@meetings = current_user.meetings.where(user_id: current_user)
end
end

# GET /meetings/1
# GET /meetings/1.json
def show
@comment = Comment.new
end

# GET /meetings/new
def new
@meeting = Meeting.new
end

# GET /meetings/1/edit
def edit
end

# POST /meetings
# POST /meetings.json
def create
@meeting = Meeting.new(meeting_params)
@meeting.user_id = current_user.id

token = params[:stripeToken]
card_brand = params[:user][:card_brand]
card_exp_month = params[:user][:card_exp_month]
card_exp_year = params[:user][:card_exp_year]
card_last4 = params[:user][:card_last4]

charge = Stripe::Charge.create(
amount: 19900,
currency: "usd",
description: "Consultly",
source: token
)

current_user.stripe_id = charge.id
current_user.card_brand = card_brand
current_user.card_exp_month = card_exp_month
current_user.card_exp_year = card_exp_year
current_user.card_last4 = card_last4
current_user.save!

respond_to do |format|
if @meeting.save
format.html { redirect_to @meeting, notice: 'Meeting was successfully created.' }
format.json { render :show, status: :created, location: @meeting }
MeetingMailer.with(meeting: @meeting, user: current_user).meeting_scheduled.deliver_later
else
format.html { render :new }
format.json { render json: @meeting.errors, status: :unprocessable_entity }
end
end

rescue Stripe::CardError => e
flash.alert = e.message
render action: :new
end

# PATCH/PUT /meetings/1
# PATCH/PUT /meetings/1.json
def update
respond_to do |format|
if @meeting.update(meeting_params)
format.html { redirect_to @meeting, notice: 'Meeting was successfully updated.' }
format.json { render :show, status: :ok, location: @meeting }
else
format.html { render :edit }
format.json { render json: @meeting.errors, status: :unprocessable_entity }
end
end
end

# DELETE /meetings/1
# DELETE /meetings/1.json
def destroy
@meeting.destroy
respond_to do |format|
format.html { redirect_to meetings_url, notice: 'Meeting was successfully destroyed.' }
format.json { head :no_content }
end
end

def active_sessions
@active_sessions = Meeting.where("end_time > ?", Time.now)
end

private
# Use callbacks to share common setup or constraints between actions.
def set_meeting
@meeting = Meeting.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def meeting_params
params.require(:meeting).permit(:name, :start_time, :end_time, :user_id)
end

def must_be_admin
unless current_user.admin?
redirect_to meetings_path, alert: "You don't have access to this page"
end
end
end
Loading

0 comments on commit 499ad85

Please sign in to comment.