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 @@
+
+
+
+
+
+ <%= render 'form', recurring_event: @recurring_event %>
+
+
+
+
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 @@
+
+
+
+
+
+ <%= render 'form', recurring_event: @recurring_event %>
+
+
+
+
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