diff --git a/Gemfile b/Gemfile index 462b06a..c785c20 100644 --- a/Gemfile +++ b/Gemfile @@ -29,3 +29,5 @@ source 'https://rails-assets.org' do gem 'rails-assets-fullcalendar' gem 'rails-assets-momentjs' end + +gem 'ice_cube' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 2c20e9f..d31bb03 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -70,6 +70,7 @@ GEM globalid (0.4.0) activesupport (>= 4.2.0) i18n (0.8.6) + ice_cube (0.16.2) jbuilder (2.7.0) activesupport (>= 4.2.0) multi_json (>= 1.2) @@ -187,6 +188,7 @@ DEPENDENCIES byebug coffee-rails (~> 4.1.0) faker + ice_cube jbuilder (~> 2.0) jquery-rails listen (~> 3.0.5) diff --git a/app/assets/javascripts/events.coffee b/app/assets/javascripts/events.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/app/assets/javascripts/events.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/full_calendar.js b/app/assets/javascripts/full_calendar.js index 0e54d18..c5e2f29 100644 --- a/app/assets/javascripts/full_calendar.js +++ b/app/assets/javascripts/full_calendar.js @@ -12,8 +12,10 @@ initialize_calendar = function() { selectHelper: true, editable: true, eventLimit: true, - events: '/events.json', - + eventSources: [ + '/events.json', + '/recurring_events.json' + ], select: function(start, end) { $.getScript('/events/new', function() { $('#event_date_range').val(moment(start).format("MM/DD/YYYY HH:mm") + ' - ' + moment(end).format("MM/DD/YYYY HH:mm")) diff --git a/app/assets/javascripts/visitors.coffee b/app/assets/javascripts/visitors.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/app/assets/javascripts/visitors.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/events.scss b/app/assets/stylesheets/events.scss deleted file mode 100644 index 04d79bd..0000000 --- a/app/assets/stylesheets/events.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the events controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/scaffolds.scss b/app/assets/stylesheets/scaffolds.scss deleted file mode 100644 index 4ce4266..0000000 --- a/app/assets/stylesheets/scaffolds.scss +++ /dev/null @@ -1,89 +0,0 @@ -body { - background-color: #fff; - color: #333; - font-family: verdana, arial, helvetica, sans-serif; - font-size: 13px; - line-height: 18px; - margin: 33px; -} - -p, ol, ul, td { - font-family: verdana, arial, helvetica, sans-serif; - font-size: 13px; - line-height: 18px; - margin: 33px; -} - -pre { - background-color: #eee; - padding: 10px; - font-size: 11px; -} - -a { - color: #000; - - &:visited { - color: #666; - } - - &:hover { - color: #fff; - background-color: #000; - } -} - -th { - padding-bottom: 5px; -} - -td { - padding-bottom: 7px; - padding-left: 5px; - padding-right: 5px; -} - -div { - &.field, &.actions { - margin-bottom: 10px; - } -} - -#notice { - color: green; -} - -.field_with_errors { - padding: 2px; - background-color: red; - display: table; -} - -#error_explanation { - width: 450px; - border: 2px solid red; - padding: 7px; - padding-bottom: 0; - margin-bottom: 20px; - background-color: #f0f0f0; - - h2 { - text-align: left; - font-weight: bold; - padding: 5px 5px 5px 15px; - font-size: 12px; - margin: -7px; - margin-bottom: 0; - background-color: #c00; - color: #fff; - } - - ul li { - font-size: 12px; - list-style: square; - } -} - -label { - display: block; -} diff --git a/app/assets/stylesheets/visitors.scss b/app/assets/stylesheets/visitors.scss deleted file mode 100644 index 2842fd0..0000000 --- a/app/assets/stylesheets/visitors.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the visitors controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/recurring_events_controller.rb b/app/controllers/recurring_events_controller.rb new file mode 100644 index 0000000..c1bdcc0 --- /dev/null +++ b/app/controllers/recurring_events_controller.rb @@ -0,0 +1,45 @@ +class RecurringEventsController < ApplicationController + before_action :set_recurring_event, only: [:show, :edit, :update, :destroy] + + def index + @recurring_events = RecurringEvent.all + end + + def show + end + + def new + @recurring_event = RecurringEvent.new + end + + def edit + end + + def create + @recurring_event = RecurringEvent.new(recurring_event_params) + @recurring_event.save + end + + def update + if params[:event] + @recurring_event.update(anchor: params[:event][:start]) + else + @recurring_event.update(recurring_event_params) + end + end + + def destroy + @recurring_event.destroy + end + + private + + def set_recurring_event + @recurring_event = RecurringEvent.find(params[:id]) + end + + def recurring_event_params + params.require(:recurring_event).permit(:title, :anchor, :frequency, :color) + end +end + diff --git a/app/helpers/recurring_events_helper.rb b/app/helpers/recurring_events_helper.rb new file mode 100644 index 0000000..bda1d59 --- /dev/null +++ b/app/helpers/recurring_events_helper.rb @@ -0,0 +1,2 @@ +module RecurringEventsHelper +end diff --git a/app/models/recurring_event.rb b/app/models/recurring_event.rb new file mode 100644 index 0000000..7d5e565 --- /dev/null +++ b/app/models/recurring_event.rb @@ -0,0 +1,43 @@ +# == Schema Information +# +# Table name: recurring_events +# +# id :integer not null, primary key +# title :string +# anchor :date +# frequency :integer default(0) +# color :string +# created_at :datetime not null +# updated_at :datetime not null +# + +class RecurringEvent < ApplicationRecord + enum frequency: { weekly: 0, biweekly: 1, monthly: 2, annually: 3 } + + validates :anchor, presence: true + validates :frequency, presence: true + + def schedule + @schedule ||= begin + schedule = IceCube::Schedule.new(now = anchor) + case frequency + when 'weekly' + schedule.add_recurrence_rule IceCube::Rule.weekly(1) + when 'biweekly' + schedule.add_recurrence_rule IceCube::Rule.weekly(2) + when 'monthly' + schedule.add_recurrence_rule IceCube::Rule.monthly(1) + when 'annually' + schedule.add_recurrence_rule IceCube::Rule.yearly(1) + end + schedule + end + end + + def events(start_date, end_date) + start_frequency = start_date ? start_date.to_date : Date.today - 1.year + end_frequency = end_date ? end_date.to_date : Date.today + 1.year + schedule.occurrences_between(start_frequency, end_frequency) + end + +end diff --git a/app/views/events/_event.json.jbuilder b/app/views/events/_event.json.jbuilder index 683d1b3..0d8f4a5 100644 --- a/app/views/events/_event.json.jbuilder +++ b/app/views/events/_event.json.jbuilder @@ -1,6 +1,6 @@ date_format = event.all_day_event? ? '%Y-%m-%d' : '%Y-%m-%dT%H:%M:%S' -json.id event.id +json.id "event_#{event.id}" json.title event.title json.start event.start.strftime(date_format) json.end event.end.strftime(date_format) diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index cf8d684..5f2abc8 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -9,6 +9,10 @@
<%= f.button :submit %> + <%= link_to 'New Recurring Event', + new_recurring_event_path, + class: 'btn btn-default', + remote: true if @event.new_record? %> <%= link_to 'Delete', event, method: :delete, diff --git a/app/views/events/destroy.js.erb b/app/views/events/destroy.js.erb index f087e91..e6af025 100644 --- a/app/views/events/destroy.js.erb +++ b/app/views/events/destroy.js.erb @@ -1,2 +1,2 @@ -$('.calendar').fullCalendar('removeEvents', [<%= @event.id %>]) +$('.calendar').fullCalendar('removeEvents', '<%= "event_#{@event.id}" %>') $('.modal').modal('hide'); diff --git a/app/views/events/new.js.erb b/app/views/events/new.js.erb index 67b068f..551279a 100644 --- a/app/views/events/new.js.erb +++ b/app/views/events/new.js.erb @@ -1,3 +1,4 @@ +$('.modal-backdrop').hide(); $('#remote_container').html('<%= j render "new" %>'); $('#new_event').modal('show'); diff --git a/app/views/events/update.js.erb b/app/views/events/update.js.erb index 7269d1e..9956035 100644 --- a/app/views/events/update.js.erb +++ b/app/views/events/update.js.erb @@ -1,4 +1,4 @@ -$('.calendar').fullCalendar('removeEvents', [<%= @event.id %>]); +$('.calendar').fullCalendar('removeEvent', '<%= "event_#{@event.id}" %>'); $('.calendar').fullCalendar( 'renderEvent', $.parseJSON("<%=j render(@event, format: :json).html_safe %>"), diff --git a/app/views/recurring_events/_edit.html.erb b/app/views/recurring_events/_edit.html.erb new file mode 100644 index 0000000..3fcae74 --- /dev/null +++ b/app/views/recurring_events/_edit.html.erb @@ -0,0 +1,13 @@ + diff --git a/app/views/recurring_events/_form.html.erb b/app/views/recurring_events/_form.html.erb new file mode 100644 index 0000000..6614470 --- /dev/null +++ b/app/views/recurring_events/_form.html.erb @@ -0,0 +1,22 @@ +<%= simple_form_for @recurring_event, remote: true do |f| %> +
+ <%= f.input :title %> + <%= f.input :anchor, input_html: { class: "form-control input-sm" } %> + <%= f.input :frequency, as: :select, collection: RecurringEvent.frequencies.keys, input_html: { class: "form-control input-sm" } %> + <%= f.input :color, as: :select, collection: [['Black','black'], ['Green','green'], ['Red','red']] %> +
+ +
+ <%= f.button :submit %> + <%= link_to 'New Event', + new_event_path, + class: 'btn btn-default', + remote: true if @recurring_event.new_record? %> + <%= link_to 'Delete', + @recurring_event, + method: :delete, + class: 'btn btn-danger', + data: { confirm: 'Are you sure?' }, + remote: true unless @recurring_event.new_record? %> +
+<% end %> diff --git a/app/views/recurring_events/_new.html.erb b/app/views/recurring_events/_new.html.erb new file mode 100644 index 0000000..9479e87 --- /dev/null +++ b/app/views/recurring_events/_new.html.erb @@ -0,0 +1,13 @@ + diff --git a/app/views/recurring_events/_recurring_event.json.jbuilder b/app/views/recurring_events/_recurring_event.json.jbuilder new file mode 100644 index 0000000..189ff42 --- /dev/null +++ b/app/views/recurring_events/_recurring_event.json.jbuilder @@ -0,0 +1,13 @@ +events = recurring_event.events(params[:start], params[:end]) +json.array! events do |event| + json.id "recurring_#{recurring_event.id}" + json.title recurring_event.title + json.start event.strftime('%Y-%m-%d') + json.end (event + 1.day).strftime('%Y-%m-%d') + + json.color recurring_event.color unless recurring_event.color.blank? + json.allDay true + + json.update_url recurring_event_path(recurring_event, method: :patch) + json.edit_url edit_recurring_event_path(recurring_event) +end \ No newline at end of file diff --git a/app/views/recurring_events/create.js.erb b/app/views/recurring_events/create.js.erb new file mode 100644 index 0000000..80199dd --- /dev/null +++ b/app/views/recurring_events/create.js.erb @@ -0,0 +1,6 @@ +$('.calendar').fullCalendar( + 'renderEvents', + $.parseJSON("<%=j render(@recurring_event, format: :json).html_safe %>"), + true +); +$('.modal').modal('hide'); diff --git a/app/views/recurring_events/destroy.js.erb b/app/views/recurring_events/destroy.js.erb new file mode 100644 index 0000000..e506736 --- /dev/null +++ b/app/views/recurring_events/destroy.js.erb @@ -0,0 +1,2 @@ +$('.calendar').fullCalendar('removeEvents', '<%= "recurring_#{@recurring_event.id}" %>'); +$('.modal').modal('hide'); diff --git a/app/views/recurring_events/edit.js.erb b/app/views/recurring_events/edit.js.erb new file mode 100644 index 0000000..4760153 --- /dev/null +++ b/app/views/recurring_events/edit.js.erb @@ -0,0 +1,3 @@ +$('#remote_container').html('<%= j render "edit" %>'); +$('#edit_recurring_event').modal('show'); + diff --git a/app/views/recurring_events/index.json.jbuilder b/app/views/recurring_events/index.json.jbuilder new file mode 100644 index 0000000..126749d --- /dev/null +++ b/app/views/recurring_events/index.json.jbuilder @@ -0,0 +1,3 @@ +json.partial! @recurring_events, + partial: 'recurring_events/recurring_event', + as: :recurring_event diff --git a/app/views/recurring_events/new.js.erb b/app/views/recurring_events/new.js.erb new file mode 100644 index 0000000..cc9b443 --- /dev/null +++ b/app/views/recurring_events/new.js.erb @@ -0,0 +1,4 @@ +$('.modal-backdrop').hide(); +$('#remote_container').html('<%= j render "new" %>'); +$('#new_recurring_event').modal('show'); + diff --git a/app/views/recurring_events/update.js.erb b/app/views/recurring_events/update.js.erb new file mode 100644 index 0000000..b303d79 --- /dev/null +++ b/app/views/recurring_events/update.js.erb @@ -0,0 +1,7 @@ +$('.calendar').fullCalendar('removeEvents', '<%= "recurring_#{@recurring_event.id}" %>'); +$('.calendar').fullCalendar( + 'renderEvents', + $.parseJSON("<%= j render(@recurring_event, format: :json).html_safe %>"), + true +); +$('.modal').modal('hide'); \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 878ede2..be6bbd2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,5 @@ Rails.application.routes.draw do + resources :recurring_events resources :events root 'visitors#index' - - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end diff --git a/db/migrate/20170819005825_create_recurring_events.rb b/db/migrate/20170819005825_create_recurring_events.rb new file mode 100644 index 0000000..9705ca5 --- /dev/null +++ b/db/migrate/20170819005825_create_recurring_events.rb @@ -0,0 +1,14 @@ +# rails g model recurring_event title anchor:date frequency:integer color + +class CreateRecurringEvents < ActiveRecord::Migration[5.0] + def change + create_table :recurring_events do |t| + t.string :title + t.date :anchor + t.integer :frequency, limit: 1, default: 0 + t.string :color + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9e5295b..370e4f2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160814032341) do +ActiveRecord::Schema.define(version: 20170819005825) do create_table "events", force: :cascade do |t| t.string "title" @@ -21,4 +21,13 @@ t.datetime "updated_at", null: false end + create_table "recurring_events", force: :cascade do |t| + t.string "title" + t.date "anchor" + t.integer "frequency", limit: 1, default: 0 + t.string "color" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + end diff --git a/test/controllers/recurring_events_controller_test.rb b/test/controllers/recurring_events_controller_test.rb new file mode 100644 index 0000000..06c157d --- /dev/null +++ b/test/controllers/recurring_events_controller_test.rb @@ -0,0 +1,48 @@ +require 'test_helper' + +class RecurringEventsControllerTest < ActionDispatch::IntegrationTest + setup do + @recurring_event = recurring_events(:one) + end + + test "should get index" do + get recurring_events_url + assert_response :success + end + + test "should get new" do + get new_recurring_event_url + assert_response :success + end + + test "should create recurring_event" do + assert_difference('RecurringEvent.count') do + post recurring_events_url, params: { recurring_event: { anchor: @recurring_event.anchor, color: @recurring_event.color, frequency: @recurring_event.frequency, title: @recurring_event.title } } + end + + assert_redirected_to recurring_event_url(RecurringEvent.last) + end + + test "should show recurring_event" do + get recurring_event_url(@recurring_event) + assert_response :success + end + + test "should get edit" do + get edit_recurring_event_url(@recurring_event) + assert_response :success + end + + test "should update recurring_event" do + patch recurring_event_url(@recurring_event), params: { recurring_event: { anchor: @recurring_event.anchor, color: @recurring_event.color, frequency: @recurring_event.frequency, title: @recurring_event.title } } + assert_redirected_to recurring_event_url(@recurring_event) + end + + test "should destroy recurring_event" do + assert_difference('RecurringEvent.count', -1) do + delete recurring_event_url(@recurring_event) + end + + assert_redirected_to recurring_events_url + end +end diff --git a/test/fixtures/recurring_events.yml b/test/fixtures/recurring_events.yml new file mode 100644 index 0000000..b498702 --- /dev/null +++ b/test/fixtures/recurring_events.yml @@ -0,0 +1,26 @@ +# == Schema Information +# +# Table name: recurring_events +# +# id :integer not null, primary key +# title :string +# anchor :date +# frequency :integer default(0) +# color :string +# created_at :datetime not null +# updated_at :datetime not null +# + +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + title: MyString + anchor: 2017-08-18 + frequency: 1 + color: MyString + +two: + title: MyString + anchor: 2017-08-18 + frequency: 1 + color: MyString diff --git a/test/models/recurring_event_test.rb b/test/models/recurring_event_test.rb new file mode 100644 index 0000000..96106ea --- /dev/null +++ b/test/models/recurring_event_test.rb @@ -0,0 +1,20 @@ +# == Schema Information +# +# Table name: recurring_events +# +# id :integer not null, primary key +# title :string +# anchor :date +# frequency :integer default(0) +# color :string +# created_at :datetime not null +# updated_at :datetime not null +# + +require 'test_helper' + +class RecurringEventTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end