From ddc8c79cada06ad65b331393f2cfab3b2d0c42b6 Mon Sep 17 00:00:00 2001 From: Kapil Chouhan Date: Sun, 2 Feb 2020 14:00:58 +0530 Subject: [PATCH] init --- .browserslistrc | 1 + .eslintrc.js | 8 + .gitignore | 38 + .ruby-version | 1 + Gemfile | 60 + Gemfile.lock | 223 + README.md | 24 + Rakefile | 6 + app/assets/config/manifest.js | 3 + app/assets/images/.keep | 0 app/assets/javascripts/application.js | 15 + app/assets/javascripts/cable.js | 13 + app/assets/javascripts/channels/.keep | 0 app/assets/stylesheets/application.css | 15 + app/channels/application_cable/channel.rb | 4 + app/channels/application_cable/connection.rb | 4 + app/controllers/api/events_controller.rb | 39 + app/controllers/application_controller.rb | 3 + app/controllers/concerns/.keep | 0 app/controllers/site_controller.rb | 2 + app/helpers/application_helper.rb | 2 + app/javascript/components/App.css | 189 + app/javascript/components/App.js | 14 + app/javascript/components/Editor.js | 126 + app/javascript/components/Event.js | 61 + app/javascript/components/EventForm.js | 201 + app/javascript/components/EventList.js | 78 + app/javascript/components/EventNotFound.js | 5 + app/javascript/components/Header.js | 9 + app/javascript/components/PropsRoute.js | 18 + app/javascript/helpers/helpers.js | 49 + app/javascript/helpers/notifications.js | 36 + app/javascript/packs/application.js | 30 + app/javascript/packs/hello_react.jsx | 26 + app/jobs/application_job.rb | 2 + app/mailers/application_mailer.rb | 4 + app/models/application_record.rb | 3 + app/models/concerns/.keep | 0 app/models/event.rb | 2 + app/views/layouts/application.html.erb | 14 + app/views/layouts/mailer.html.erb | 13 + app/views/layouts/mailer.text.erb | 1 + app/views/site/index.html.erb | 1 + babel.config.js | 87 + bin/bundle | 3 + bin/rails | 9 + bin/rake | 9 + bin/setup | 36 + bin/spring | 17 + bin/update | 31 + bin/webpack | 18 + bin/webpack-dev-server | 18 + bin/yarn | 11 + config.ru | 5 + config/application.rb | 19 + config/boot.rb | 4 + config/cable.yml | 10 + config/credentials.yml.enc | 1 + config/database.yml | 22 + config/environment.rb | 5 + config/environments/development.rb | 61 + config/environments/production.rb | 94 + config/environments/test.rb | 46 + .../application_controller_renderer.rb | 8 + config/initializers/assets.rb | 14 + config/initializers/backtrace_silencers.rb | 7 + .../initializers/content_security_policy.rb | 25 + config/initializers/cookies_serializer.rb | 5 + .../initializers/filter_parameter_logging.rb | 4 + config/initializers/inflections.rb | 16 + config/initializers/mime_types.rb | 4 + config/initializers/wrap_parameters.rb | 14 + config/locales/en.yml | 33 + config/puma.rb | 37 + config/routes.rb | 13 + config/spring.rb | 6 + config/storage.yml | 34 + config/webpack/development.js | 5 + config/webpack/environment.js | 3 + config/webpack/production.js | 5 + config/webpack/test.js | 5 + config/webpacker.yml | 97 + db/migrate/20200201172244_create_events.rb | 14 + db/schema.rb | 29 + db/seeds.rb | 11 + db/seeds/events.json | 50 + lib/assets/.keep | 0 lib/tasks/.keep | 0 log/.keep | 0 package.json | 23 + postcss.config.js | 12 + public/404.html | 67 + public/422.html | 67 + public/500.html | 66 + public/apple-touch-icon-precomposed.png | 0 public/apple-touch-icon.png | 0 public/favicon.ico | 0 public/robots.txt | 1 + storage/.keep | 0 test/application_system_test_case.rb | 5 + test/controllers/.keep | 0 test/fixtures/.keep | 0 test/fixtures/events.yml | 17 + test/fixtures/files/.keep | 0 test/helpers/.keep | 0 test/integration/.keep | 0 test/mailers/.keep | 0 test/models/.keep | 0 test/models/event_test.rb | 7 + test/system/.keep | 0 test/test_helper.rb | 10 + tmp/.keep | 0 vendor/.keep | 0 yarn.lock | 7153 +++++++++++++++++ 114 files changed, 9716 insertions(+) create mode 100644 .browserslistrc create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 .ruby-version create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 README.md create mode 100644 Rakefile create mode 100644 app/assets/config/manifest.js create mode 100644 app/assets/images/.keep create mode 100644 app/assets/javascripts/application.js create mode 100644 app/assets/javascripts/cable.js create mode 100644 app/assets/javascripts/channels/.keep create mode 100644 app/assets/stylesheets/application.css create mode 100644 app/channels/application_cable/channel.rb create mode 100644 app/channels/application_cable/connection.rb create mode 100644 app/controllers/api/events_controller.rb create mode 100644 app/controllers/application_controller.rb create mode 100644 app/controllers/concerns/.keep create mode 100644 app/controllers/site_controller.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 app/javascript/components/App.css create mode 100644 app/javascript/components/App.js create mode 100644 app/javascript/components/Editor.js create mode 100644 app/javascript/components/Event.js create mode 100644 app/javascript/components/EventForm.js create mode 100644 app/javascript/components/EventList.js create mode 100644 app/javascript/components/EventNotFound.js create mode 100644 app/javascript/components/Header.js create mode 100644 app/javascript/components/PropsRoute.js create mode 100644 app/javascript/helpers/helpers.js create mode 100644 app/javascript/helpers/notifications.js create mode 100644 app/javascript/packs/application.js create mode 100644 app/javascript/packs/hello_react.jsx create mode 100644 app/jobs/application_job.rb create mode 100644 app/mailers/application_mailer.rb create mode 100644 app/models/application_record.rb create mode 100644 app/models/concerns/.keep create mode 100644 app/models/event.rb create mode 100644 app/views/layouts/application.html.erb create mode 100644 app/views/layouts/mailer.html.erb create mode 100644 app/views/layouts/mailer.text.erb create mode 100644 app/views/site/index.html.erb create mode 100644 babel.config.js create mode 100755 bin/bundle create mode 100755 bin/rails create mode 100755 bin/rake create mode 100755 bin/setup create mode 100755 bin/spring create mode 100755 bin/update create mode 100755 bin/webpack create mode 100755 bin/webpack-dev-server create mode 100755 bin/yarn create mode 100644 config.ru create mode 100644 config/application.rb create mode 100644 config/boot.rb create mode 100644 config/cable.yml create mode 100644 config/credentials.yml.enc create mode 100644 config/database.yml create mode 100644 config/environment.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/initializers/application_controller_renderer.rb create mode 100644 config/initializers/assets.rb create mode 100644 config/initializers/backtrace_silencers.rb create mode 100644 config/initializers/content_security_policy.rb create mode 100644 config/initializers/cookies_serializer.rb create mode 100644 config/initializers/filter_parameter_logging.rb create mode 100644 config/initializers/inflections.rb create mode 100644 config/initializers/mime_types.rb create mode 100644 config/initializers/wrap_parameters.rb create mode 100644 config/locales/en.yml create mode 100644 config/puma.rb create mode 100644 config/routes.rb create mode 100644 config/spring.rb create mode 100644 config/storage.yml create mode 100644 config/webpack/development.js create mode 100644 config/webpack/environment.js create mode 100644 config/webpack/production.js create mode 100644 config/webpack/test.js create mode 100644 config/webpacker.yml create mode 100644 db/migrate/20200201172244_create_events.rb create mode 100644 db/schema.rb create mode 100644 db/seeds.rb create mode 100644 db/seeds/events.json create mode 100644 lib/assets/.keep create mode 100644 lib/tasks/.keep create mode 100644 log/.keep create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 public/404.html create mode 100644 public/422.html create mode 100644 public/500.html create mode 100644 public/apple-touch-icon-precomposed.png create mode 100644 public/apple-touch-icon.png create mode 100644 public/favicon.ico create mode 100644 public/robots.txt create mode 100644 storage/.keep create mode 100644 test/application_system_test_case.rb create mode 100644 test/controllers/.keep create mode 100644 test/fixtures/.keep create mode 100644 test/fixtures/events.yml create mode 100644 test/fixtures/files/.keep create mode 100644 test/helpers/.keep create mode 100644 test/integration/.keep create mode 100644 test/mailers/.keep create mode 100644 test/models/.keep create mode 100644 test/models/event_test.rb create mode 100644 test/system/.keep create mode 100644 test/test_helper.rb create mode 100644 tmp/.keep create mode 100644 vendor/.keep create mode 100644 yarn.lock diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..e94f814 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1 @@ +defaults diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..d7c5932 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + extends: 'airbnb', + rules: { + 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], + 'no-console': 0, + 'no-alert': 0, + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aea2bd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-journal + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore uploaded files in development +/storage/* +!/storage/.keep + +/node_modules +/yarn-error.log + +/public/assets +.byebug_history + +# Ignore master key for decrypting credentials and more. +/config/master.key + +/public/packs +/public/packs-test +/node_modules +/yarn-error.log +yarn-debug.log* +.yarn-integrity diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..79838de --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.5.3 \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..542d4b9 --- /dev/null +++ b/Gemfile @@ -0,0 +1,60 @@ +source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby '2.5.3' + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 5.2.4', '>= 5.2.4.1' +gem 'pg' +# Use Puma as the app server +gem 'puma', '~> 3.11' +# Use SCSS for stylesheets +gem 'sass-rails', '~> 5.0' +# Use Uglifier as compressor for JavaScript assets +gem 'uglifier', '>= 1.3.0' +# See https://github.com/rails/execjs#readme for more supported runtimes +# gem 'mini_racer', platforms: :ruby +gem 'responders' +# Use CoffeeScript for .coffee assets and views +gem 'coffee-rails', '~> 4.2' + +# 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' +# Use ActiveModel has_secure_password +# gem 'bcrypt', '~> 3.1.7' +gem 'webpacker', '>= 4.0.x' +# Use ActiveStorage variant +# gem 'mini_magick', '~> 4.8' + +# Use Capistrano for deployment +# gem 'capistrano-rails', group: :development + +# Reduces boot times through caching; required in config/boot.rb +gem 'bootsnap', '>= 1.1.0', require: false + +group :development, :test do + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] +end + +group :development do + # Access an interactive console on exception pages or by calling 'console' anywhere in the code. + gem 'web-console', '>= 3.3.0' + gem 'listen', '>= 3.0.5', '< 3.2' + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'spring' + gem 'spring-watcher-listen', '~> 2.0.0' +end + +group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '>= 2.15' + gem 'selenium-webdriver' + # Easy installation and use of chromedriver to run system tests with Chrome + gem 'chromedriver-helper' +end + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..c1a3df3 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,223 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.2.4.1) + actionpack (= 5.2.4.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailer (5.2.4.1) + actionpack (= 5.2.4.1) + actionview (= 5.2.4.1) + activejob (= 5.2.4.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.2.4.1) + actionview (= 5.2.4.1) + activesupport (= 5.2.4.1) + rack (~> 2.0, >= 2.0.8) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.2.4.1) + activesupport (= 5.2.4.1) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.2.4.1) + activesupport (= 5.2.4.1) + globalid (>= 0.3.6) + activemodel (5.2.4.1) + activesupport (= 5.2.4.1) + activerecord (5.2.4.1) + activemodel (= 5.2.4.1) + activesupport (= 5.2.4.1) + arel (>= 9.0) + activestorage (5.2.4.1) + actionpack (= 5.2.4.1) + activerecord (= 5.2.4.1) + marcel (~> 0.3.1) + activesupport (5.2.4.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + archive-zip (0.12.0) + io-like (~> 0.3.0) + arel (9.0.0) + bindex (0.8.1) + bootsnap (1.4.5) + msgpack (~> 1.0) + builder (3.2.4) + byebug (11.1.1) + capybara (3.31.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.5) + xpath (~> 3.2) + childprocess (3.0.0) + chromedriver-helper (2.1.1) + archive-zip (~> 0.10) + nokogiri (~> 1.8) + coffee-rails (4.2.2) + coffee-script (>= 2.2.0) + railties (>= 4.0.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + concurrent-ruby (1.1.5) + crass (1.0.6) + erubi (1.9.0) + execjs (2.7.0) + ffi (1.12.2) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (1.8.2) + concurrent-ruby (~> 1.0) + io-like (0.3.0) + jbuilder (2.9.1) + activesupport (>= 4.2.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.4.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) + method_source (0.9.2) + mimemagic (0.3.4) + mini_mime (1.0.2) + mini_portile2 (2.4.0) + minitest (5.14.0) + msgpack (1.3.1) + nio4r (2.5.2) + nokogiri (1.10.7) + mini_portile2 (~> 2.4.0) + pg (1.2.2) + public_suffix (4.0.3) + puma (3.12.2) + rack (2.1.2) + rack-proxy (0.6.5) + rack + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (5.2.4.1) + actioncable (= 5.2.4.1) + actionmailer (= 5.2.4.1) + actionpack (= 5.2.4.1) + actionview (= 5.2.4.1) + activejob (= 5.2.4.1) + activemodel (= 5.2.4.1) + activerecord (= 5.2.4.1) + activestorage (= 5.2.4.1) + activesupport (= 5.2.4.1) + bundler (>= 1.3.0) + railties (= 5.2.4.1) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (5.2.4.1) + actionpack (= 5.2.4.1) + activesupport (= 5.2.4.1) + method_source + rake (>= 0.8.7) + thor (>= 0.19.0, < 2.0) + rake (13.0.1) + rb-fsevent (0.10.3) + rb-inotify (0.10.1) + ffi (~> 1.0) + regexp_parser (1.6.0) + responders (2.4.0) + actionpack (>= 4.2.0, < 5.3) + railties (>= 4.2.0, < 5.3) + ruby_dep (1.5.0) + rubyzip (2.2.0) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.1.0) + railties (>= 5.2.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + selenium-webdriver (3.142.7) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + spring (2.1.0) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + thor (1.0.1) + thread_safe (0.3.6) + tilt (2.0.10) + tzinfo (1.2.6) + thread_safe (~> 0.1) + uglifier (4.2.0) + execjs (>= 0.3.0, < 3) + web-console (3.7.0) + actionview (>= 5.0) + activemodel (>= 5.0) + bindex (>= 0.4.0) + railties (>= 5.0) + webpacker (4.2.2) + activesupport (>= 4.2) + rack-proxy (>= 0.6.1) + railties (>= 4.2) + websocket-driver (0.7.1) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.4) + xpath (3.2.0) + nokogiri (~> 1.8) + +PLATFORMS + ruby + +DEPENDENCIES + bootsnap (>= 1.1.0) + byebug + capybara (>= 2.15) + chromedriver-helper + coffee-rails (~> 4.2) + jbuilder (~> 2.5) + listen (>= 3.0.5, < 3.2) + pg + puma (~> 3.11) + rails (~> 5.2.4, >= 5.2.4.1) + responders + sass-rails (~> 5.0) + selenium-webdriver + spring + spring-watcher-listen (~> 2.0.0) + tzinfo-data + uglifier (>= 1.3.0) + web-console (>= 3.3.0) + webpacker (>= 4.0.x) + +RUBY VERSION + ruby 2.5.3p105 + +BUNDLED WITH + 2.1.4 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..e85f913 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000..b16e53d --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000..43ba7e9 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,15 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's +// vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require rails-ujs +//= require activestorage +//= require_tree . diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 0000000..739aa5f --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/assets/javascripts/channels/.keep b/app/assets/javascripts/channels/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 0000000..d05ea0f --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/events_controller.rb b/app/controllers/api/events_controller.rb new file mode 100644 index 0000000..1404182 --- /dev/null +++ b/app/controllers/api/events_controller.rb @@ -0,0 +1,39 @@ +class Api::EventsController < ApplicationController + respond_to :json + + def index + respond_with Event.order(event_date: :DESC) + end + + def show + respond_with Event.find(params[:id]) + end + + def create + respond_with :api, Event.create(event_params) + end + + def destroy + respond_with Event.destroy(params[:id]) + end + + def update + event = Event.find(params['id']) + event.update(event_params) + respond_with Event, json: event + end + + private + + def event_params + params.require(:event).permit( + :id, + :event_type, + :event_date, + :title, + :speaker, + :host, + :published + ) + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..0491b0a --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,3 @@ +class ApplicationController < ActionController::Base + protect_from_forgery with: :null_session +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/controllers/site_controller.rb b/app/controllers/site_controller.rb new file mode 100644 index 0000000..eebb233 --- /dev/null +++ b/app/controllers/site_controller.rb @@ -0,0 +1,2 @@ +class SiteController < ApplicationController +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..de6be79 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/javascript/components/App.css b/app/javascript/components/App.css new file mode 100644 index 0000000..b8a8a18 --- /dev/null +++ b/app/javascript/components/App.css @@ -0,0 +1,189 @@ +@import url("https://fonts.googleapis.com/css?family=Roboto:400,700,300,400italic"); +@import url("https://fonts.googleapis.com/css?family=Maven+Pro:400,500,700"); + +body, html, div, blockquote, img, label, p, h1, h2, h3, h4, h5, h6, pre, ul, ol, li, dl, dt, dd, form, a, fieldset, input, th, td { + margin: 0; + padding: 0; +} + +ul, ol { + list-style: none; +} + +body { + font-family: Roboto; + font-size: 16px; + line-height: 28px; +} + +header { + background: #f57011; + height: 60px; +} + +header h1, header h1 a{ + display: inline-block; + font-family: "Maven Pro"; + font-size: 28px; + font-weight: 500; + color: white; + padding: 14px 5%; + text-decoration: none; +} + +header h1 a:hover { + text-decoration: underline; +} + +.grid { + display: grid; + grid-gap: 50px; + grid-template-columns: 25% auto; + margin: 25px auto; + width: 90%; + height: calc(100vh - 145px); +} + +.eventList { + background: #f6f6f6; + padding: 16px; +} + +.eventList h2 { + font-size: 20px; + padding: 8px 6px 10px; +} + +.eventContainer { + font-size: 15px; + line-height: 35px; +} + +.eventContainer h2 { + margin-bottom: 10px; +} + +.eventList li:hover, a.active { + background: #f8e5ce; +} + +.eventList a { + display: block; + color: black; + text-decoration: none; + border-bottom: 1px solid #dddddd; + padding: 8px 6px 10px; + outline: 0; +} + +.eventList h2 > a { + color: #236fff; + font-size: 15px; + float: right; + font-weight: normal; + border-bottom: none; + padding: 0px; +} + +.eventForm { + margin-top: 15px; +} + +label > strong { + display: inline-block; + vertical-align: top; + text-align: right; + width: 100px; + margin-right: 6px; + font-size: 15px; +} + +input, textarea { + padding: 2px 0 3px 3px; + width: 400px; + margin-bottom: 15px; + box-sizing: border-box; +} + +input[type="checkbox"] { + width: 13px; +} + +button[type="submit"] { + background: #f57011; + border: none; + padding: 5px 25px 8px; + font-weight: 500; + color: white; + cursor: pointer; + margin: 10px 0 0 106px; +} + +.errors { + border: 1px solid red; + border-radius: 5px; + margin: 20px 0 35px 0; + width: 513px; +} + +.errors h3 { + background: red; + color: white; + padding: 10px; + font-size: 15px; +} + +.errors ul li { + list-style-type: none; + margin: 0; + padding: 8px 0 8px 10px; + border-top: solid 1px pink; + font-size: 12px; + font-weight: 0.9; +} + +button.delete { + background: none !important; + border: none; + padding: 0 !important; + margin-left: 10px; + cursor: pointer; + color: #236fff; + font-size: 15px; + font-weight: normal; + margin: 3px 0 0 0; + text-decoration: none; +} + +button.delete:hover { + text-decoration: underline; +} + +h2 a { + color: #236fff; + font-size: 15px; + font-weight: normal; + margin: 3px 12px 0 12px; + text-decoration: none; +} + +h2 a:hover { + text-decoration: underline; +} + +.form-actions a { + color: #236fff; + font-size: 15px; + margin: 3px 12px 0 12px; + text-decoration: none; +} + +.form-actions a:hover { + text-decoration: underline; +} + +input.search { + width: 92%; + margin: 15px 2px; + padding: 4px 0 6px 6px; +} \ No newline at end of file diff --git a/app/javascript/components/App.js b/app/javascript/components/App.js new file mode 100644 index 0000000..60c34d5 --- /dev/null +++ b/app/javascript/components/App.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { Route } from 'react-router-dom'; +import { Alert } from '../helpers/notifications'; +import Editor from './Editor'; +import './App.css'; + +const App = () => ( +
+ + +
+); + +export default App; diff --git a/app/javascript/components/Editor.js b/app/javascript/components/Editor.js new file mode 100644 index 0000000..9bf6983 --- /dev/null +++ b/app/javascript/components/Editor.js @@ -0,0 +1,126 @@ +import React from 'react'; +import axios from 'axios'; +import Header from './Header'; +import EventList from './EventList'; +import PropTypes from 'prop-types'; +import PropsRoute from './PropsRoute'; +import Event from './Event'; +import { Switch } from 'react-router-dom'; +import { success } from '../helpers/notifications'; +import EventForm from './EventForm'; +import { handleAjaxError } from '../helpers/helpers'; + +class Editor extends React.Component { + constructor(props) { + super(props); + + this.state = { + events: null, + }; + + this.addEvent = this.addEvent.bind(this); + this.deleteEvent = this.deleteEvent.bind(this); + this.updateEvent = this.updateEvent.bind(this); + } + + componentDidMount() { + axios + .get('/api/events.json') + .then(response => this.setState({ events: response.data })) + .catch(handleAjaxError); + } + + addEvent(newEvent) { + axios + .post('/api/events.json', newEvent) + .then((response) => { + success('Event Added!'); + const savedEvent = response.data; + this.setState(prevState => ({ + events: [...prevState.events, savedEvent], + })); + const { history } = this.props; + history.push(`/events/${savedEvent.id}`); + }) + .catch(handleAjaxError); + } + + updateEvent(updatedEvent) { + axios + .put(`/api/events/${updatedEvent.id}.json`, updatedEvent) + .then(() => { + success('Event updated'); + const { events } = this.state; + const idx = events.findIndex(event => event.id === updatedEvent.id); + events[idx] = updatedEvent; + const { history } = this.props; + history.push(`/events/${updatedEvent.id}`); + this.setState({ events }); + }) + .catch(handleAjaxError); + } + + deleteEvent(eventId) { + const sure = window.confirm('Are you sure?'); + if (sure) { + axios + .delete(`/api/events/${eventId}.json`) + .then((response) => { + if (response.status === 204) { + success('Event deleted'); + const { history } = this.props; + history.push('/events'); + + const { events } = this.state; + this.setState({ events: events.filter(event => event.id !== eventId) }); + } + }) + .catch(handleAjaxError); + } + } + + render() { + const { events } = this.state; + if (events === null) return null; + + const { match } = this.props; + const eventId = match.params.id; + const event = events.find(e => e.id === Number(eventId)); + + return ( +
+
+
+ + + + + + +
+
+ ); + } +} + +Editor.propTypes = { + match: PropTypes.shape(), + history: PropTypes.shape({ push: PropTypes.func }).isRequired, +}; + +Editor.defaultProps = { + match: undefined, +}; + +export default Editor; diff --git a/app/javascript/components/Event.js b/app/javascript/components/Event.js new file mode 100644 index 0000000..b0d0581 --- /dev/null +++ b/app/javascript/components/Event.js @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; +import EventNotFound from './EventNotFound'; + +const Event = ({ event, onDelete }) => ( +
+

+ {event.event_date} + {' - '} + {event.event_type} + Edit + +

+ +
+); + +Event.propTypes = { + event: PropTypes.shape(), + onDelete: PropTypes.func.isRequired, +}; + +Event.defaultProps = { + event: undefined, +}; + +export default Event; diff --git a/app/javascript/components/EventForm.js b/app/javascript/components/EventForm.js new file mode 100644 index 0000000..713cd5f --- /dev/null +++ b/app/javascript/components/EventForm.js @@ -0,0 +1,201 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { formatDate, isEmptyObject, validateEvent } from '../helpers/helpers'; +import Pikaday from 'pikaday'; +import 'pikaday/css/pikaday.css'; +import { Link } from 'react-router-dom'; +import EventNotFound from './EventNotFound'; + +class EventForm extends React.Component { + constructor(props) { + super(props); + + this.state = { + event: props.event, + errors: {}, + }; + + this.dateInput = React.createRef(); + this.handleSubmit = this.handleSubmit.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + } + + componentDidMount() { + new Pikaday({ + field: this.dateInput.current, + toString: date => formatDate(date), + onSelect: (date) => { + const formattedDate = formatDate(date); + this.dateInput.current.value = formattedDate; + this.updateEvent('event_date', formattedDate); + }, + }); + } + + componentWillReceiveProps({ event }) { + this.setState({ event }); + } + + handleSubmit(e) { + e.preventDefault(); + const { event } = this.state; + const errors = validateEvent(event); + + if (!isEmptyObject(errors)) { + this.setState({ errors }); + } else { + const { onSubmit } = this.props; + onSubmit(event); + } + } + + handleInputChange(event) { + const { target } = event; + const { name } = target; + const value = target.type === 'checkbox' ? target.checked : target.value; + this.updateEvent(name, value); + } + + renderErrors() { + const { errors } = this.state; + + if (isEmptyObject(errors)) { + return null; + } + + return ( +
+

The following errors prohibited the event from being saved:

+ +
+ ); + } + + updateEvent(key, value) { + this.setState(prevState => ({ + event: { + ...prevState.event, + [key]: value, + }, + })); + } + + render() { + const { event } = this.state; + const { path } = this.props; + if (!event.id && path === '/events/:id/edit') return ; + const cancelURL = event.id ? `/events/${event.id}` : '/events'; + const title = event.id ? `${event.event_date} - ${event.event_type}` : 'New Event'; + + return ( +
+

{title}

+ {this.renderErrors()} +
+
+ +
+
+ +
+
+