From 79fca14fde37d5e7f328b225f5ee21e7df3b64f1 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Wed, 11 May 2022 18:58:28 -0400 Subject: [PATCH 1/9] feat: add homepage rails g controller Homepage index --- app/assets/stylesheets/homepage.scss | 3 +++ app/controllers/homepage_controller.rb | 4 ++++ app/helpers/homepage_helper.rb | 2 ++ app/views/homepage/index.html.erb | 2 ++ config/routes.rb | 1 + test/controllers/homepage_controller_test.rb | 8 ++++++++ 6 files changed, 20 insertions(+) create mode 100644 app/assets/stylesheets/homepage.scss create mode 100644 app/controllers/homepage_controller.rb create mode 100644 app/helpers/homepage_helper.rb create mode 100644 app/views/homepage/index.html.erb create mode 100644 test/controllers/homepage_controller_test.rb diff --git a/app/assets/stylesheets/homepage.scss b/app/assets/stylesheets/homepage.scss new file mode 100644 index 0000000..3cf278d --- /dev/null +++ b/app/assets/stylesheets/homepage.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Homepage controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ diff --git a/app/controllers/homepage_controller.rb b/app/controllers/homepage_controller.rb new file mode 100644 index 0000000..e09cc6e --- /dev/null +++ b/app/controllers/homepage_controller.rb @@ -0,0 +1,4 @@ +class HomepageController < ApplicationController + def index + end +end diff --git a/app/helpers/homepage_helper.rb b/app/helpers/homepage_helper.rb new file mode 100644 index 0000000..c5bbfe5 --- /dev/null +++ b/app/helpers/homepage_helper.rb @@ -0,0 +1,2 @@ +module HomepageHelper +end diff --git a/app/views/homepage/index.html.erb b/app/views/homepage/index.html.erb new file mode 100644 index 0000000..193609f --- /dev/null +++ b/app/views/homepage/index.html.erb @@ -0,0 +1,2 @@ +

Homepage#index

+

Find me in app/views/homepage/index.html.erb

diff --git a/config/routes.rb b/config/routes.rb index c06383a..82c50f3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,3 +1,4 @@ Rails.application.routes.draw do + get 'homepage/index' # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end diff --git a/test/controllers/homepage_controller_test.rb b/test/controllers/homepage_controller_test.rb new file mode 100644 index 0000000..46b437e --- /dev/null +++ b/test/controllers/homepage_controller_test.rb @@ -0,0 +1,8 @@ +require "test_helper" + +class HomepageControllerTest < ActionDispatch::IntegrationTest + test "should get index" do + get homepage_index_url + assert_response :success + end +end From 2a39370748b71ddced4237307fef7da001541505 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Wed, 11 May 2022 19:13:19 -0400 Subject: [PATCH 2/9] chore: add Task model rails generate model Task description:string rails db:migrate --- app/models/task.rb | 2 ++ db/migrate/20220513160046_create_tasks.rb | 9 +++++++++ db/schema.rb | 24 +++++++++++++++++++++++ test/fixtures/tasks.yml | 7 +++++++ test/models/task_test.rb | 7 +++++++ 5 files changed, 49 insertions(+) create mode 100644 app/models/task.rb create mode 100644 db/migrate/20220513160046_create_tasks.rb create mode 100644 db/schema.rb create mode 100644 test/fixtures/tasks.yml create mode 100644 test/models/task_test.rb diff --git a/app/models/task.rb b/app/models/task.rb new file mode 100644 index 0000000..3c23424 --- /dev/null +++ b/app/models/task.rb @@ -0,0 +1,2 @@ +class Task < ApplicationRecord +end diff --git a/db/migrate/20220513160046_create_tasks.rb b/db/migrate/20220513160046_create_tasks.rb new file mode 100644 index 0000000..24d6c6d --- /dev/null +++ b/db/migrate/20220513160046_create_tasks.rb @@ -0,0 +1,9 @@ +class CreateTasks < ActiveRecord::Migration[6.1] + def change + create_table :tasks do |t| + t.string :description + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..f1dd0b6 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,24 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 2022_05_13_160046) do + + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "tasks", force: :cascade do |t| + t.string "description" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + +end diff --git a/test/fixtures/tasks.yml b/test/fixtures/tasks.yml new file mode 100644 index 0000000..1aad50f --- /dev/null +++ b/test/fixtures/tasks.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + description: MyString + +two: + description: MyString diff --git a/test/models/task_test.rb b/test/models/task_test.rb new file mode 100644 index 0000000..29982eb --- /dev/null +++ b/test/models/task_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class TaskTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From edf92fa5be88d03af37cccc4162fb387959ed42d Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Wed, 11 May 2022 19:20:50 -0400 Subject: [PATCH 3/9] feat: add tasks controller --- app/controllers/api/v1/tasks_controller.rb | 38 ++++++++++++++++++++++ app/controllers/application_controller.rb | 1 + config/routes.rb | 6 ++++ 3 files changed, 45 insertions(+) create mode 100644 app/controllers/api/v1/tasks_controller.rb diff --git a/app/controllers/api/v1/tasks_controller.rb b/app/controllers/api/v1/tasks_controller.rb new file mode 100644 index 0000000..4ebfda8 --- /dev/null +++ b/app/controllers/api/v1/tasks_controller.rb @@ -0,0 +1,38 @@ +class Api::V1::TasksController < ApplicationController + def index + tasks = Task.all.order(created_at: :desc) + render json: tasks + end + + def create + task = Task.create!(task_params) + if task + render json: task + else + render json: task.errors + end + end + + def show + if task + render json: task + else + render json: task.errors + end + end + + def destroy + task&.destroy + render json: { message: 'Task deleted!' } + end + + private + + def task_params + params.permit(:description, :completed) + end + + def task + @task ||= Task.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 09705d1..75f1154 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,3 @@ class ApplicationController < ActionController::Base + skip_before_action :verify_authenticity_token end diff --git a/config/routes.rb b/config/routes.rb index 82c50f3..fed6018 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,10 @@ Rails.application.routes.draw do get 'homepage/index' # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html + + namespace :api do + namespace :v1 do + resources :tasks, only: [ :index, :show, :create, :destroy] + end + end end From 7320d81c6f3b604a32d8133b28bdfe6d0fcc7e67 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Fri, 13 May 2022 10:06:13 -0400 Subject: [PATCH 4/9] chore: install tailwind https://tailwindcss.com/docs/guides/ruby-on-rails --- .gitignore | 3 +++ Gemfile | 2 ++ Gemfile.lock | 3 +++ Procfile.dev | 2 ++ app/assets/builds/.keep | 0 app/assets/config/manifest.js | 1 + .../stylesheets/application.tailwind.css | 13 ++++++++++++ app/views/layouts/application.html.erb | 5 ++++- bin/dev | 9 ++++++++ config/tailwind.config.js | 21 +++++++++++++++++++ 10 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Procfile.dev create mode 100644 app/assets/builds/.keep create mode 100644 app/assets/stylesheets/application.tailwind.css create mode 100755 bin/dev create mode 100644 config/tailwind.config.js diff --git a/.gitignore b/.gitignore index f22dd34..7357ece 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ /yarn-error.log yarn-debug.log* .yarn-integrity + +/app/assets/builds/* +!/app/assets/builds/.keep diff --git a/Gemfile b/Gemfile index 06ae301..2ad540a 100644 --- a/Gemfile +++ b/Gemfile @@ -54,3 +54,5 @@ end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +gem "tailwindcss-rails", "~> 2.0" diff --git a/Gemfile.lock b/Gemfile.lock index af5e557..3d9416c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,6 +171,8 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) + tailwindcss-rails (2.0.8-x86_64-darwin) + railties (>= 6.0.0) thor (1.2.1) tilt (2.0.10) turbolinks (5.2.1) @@ -215,6 +217,7 @@ DEPENDENCIES sass-rails (>= 6) selenium-webdriver (>= 4.0.0.rc1) spring + tailwindcss-rails (~> 2.0) turbolinks (~> 5) tzinfo-data web-console (>= 4.1.0) diff --git a/Procfile.dev b/Procfile.dev new file mode 100644 index 0000000..023e98a --- /dev/null +++ b/Procfile.dev @@ -0,0 +1,2 @@ +web: bin/rails server -p 3000 +css: bin/rails tailwindcss:watch diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 5918193..338a0e8 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,2 +1,3 @@ //= link_tree ../images //= link_directory ../stylesheets .css +//= link_tree ../builds diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css new file mode 100644 index 0000000..8666d2f --- /dev/null +++ b/app/assets/stylesheets/application.tailwind.css @@ -0,0 +1,13 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* + +@layer components { + .btn-primary { + @apply py-2 px-4 bg-blue-200; + } +} + +*/ diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 3046e61..a00d910 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -5,12 +5,15 @@ <%= csrf_meta_tags %> <%= csp_meta_tag %> + <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> - <%= yield %> +
+ <%= yield %> +
diff --git a/bin/dev b/bin/dev new file mode 100755 index 0000000..2daf776 --- /dev/null +++ b/bin/dev @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +if ! command -v foreman &> /dev/null +then + echo "Installing foreman..." + gem install foreman +fi + +foreman start -f Procfile.dev diff --git a/config/tailwind.config.js b/config/tailwind.config.js new file mode 100644 index 0000000..1db831e --- /dev/null +++ b/config/tailwind.config.js @@ -0,0 +1,21 @@ +const defaultTheme = require('tailwindcss/defaultTheme') + +module.exports = { + content: [ + './app/helpers/**/*.rb', + './app/javascript/**/*.{js,jsx}', + './app/views/**/*.{erb,haml,html,slim}' + ], + theme: { + extend: { + fontFamily: { + sans: ['Inter var', ...defaultTheme.fontFamily.sans], + }, + }, + }, + plugins: [ + require('@tailwindcss/forms'), + require('@tailwindcss/aspect-ratio'), + require('@tailwindcss/typography'), + ] +} From 9f61f28c79d419a05f8b18ae6f3d055659998612 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Fri, 13 May 2022 10:20:40 -0400 Subject: [PATCH 5/9] chore: add custom styles --- app/assets/stylesheets/homepage.scss | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/app/assets/stylesheets/homepage.scss b/app/assets/stylesheets/homepage.scss index 3cf278d..dd85132 100644 --- a/app/assets/stylesheets/homepage.scss +++ b/app/assets/stylesheets/homepage.scss @@ -1,3 +1,74 @@ // Place all the styles related to the Homepage controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: https://sass-lang.com/ + +.main-container { + padding: 1.25rem; +} + +.title { + font-weight: 700; + font-size: 1.875rem; + line-height: 2.25rem; +} + +.new-task { + margin-top: 1.25rem; + margin-bottom: 1.25rem; +} + +label { + color: rgb(17, 24, 39) +} + +.task-input { + border-width: 1px; + border-color: rgb(209, 213, 219); + padding: 0.25rem; + margin-right: 0.5rem; + border-radius: 0.375rem; +} + +.add-task { + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + background-color: #3B82F6; + color: #ffffff; + border-radius: 0.375rem; +} + +.task-container { + display: flex; + padding: 0.25rem; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + max-width: 20rem; + border-radius: 0.375rem; +} + +.task-container:hover { + background-color: #F3F4F6; +} + +.task-subcontainer { + display: flex; + flex-direction: row; + align-items: center; +} + +.checkbox { + margin-right: 0.5rem; + border-radius: 0.125rem; +} + +.description { + color: #111827; +} + +.remove-button { + margin-right: 0.5rem; +} \ No newline at end of file From 6054e8c6cb6b2504d7fcb9e9ba9b7b7f44340ac0 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Wed, 11 May 2022 19:08:06 -0400 Subject: [PATCH 6/9] feat: add initial React component --- app/javascript/components/Home.jsx | 10 ++++++++++ app/javascript/packs/Index.jsx | 9 +++++++++ app/javascript/packs/hello_react.jsx | 26 -------------------------- app/views/homepage/index.html.erb | 2 -- app/views/layouts/application.html.erb | 1 + 5 files changed, 20 insertions(+), 28 deletions(-) create mode 100644 app/javascript/components/Home.jsx create mode 100644 app/javascript/packs/Index.jsx delete mode 100644 app/javascript/packs/hello_react.jsx diff --git a/app/javascript/components/Home.jsx b/app/javascript/components/Home.jsx new file mode 100644 index 0000000..eaf9f66 --- /dev/null +++ b/app/javascript/components/Home.jsx @@ -0,0 +1,10 @@ +import React from "react"; + +export default () => ( +
+

Hola mundo!

+

+ Vamos a hacer una app con React. +

+
+); \ No newline at end of file diff --git a/app/javascript/packs/Index.jsx b/app/javascript/packs/Index.jsx new file mode 100644 index 0000000..6ba8e2f --- /dev/null +++ b/app/javascript/packs/Index.jsx @@ -0,0 +1,9 @@ +import React from 'react' +import { createRoot } from 'react-dom/client'; +import Home from '../components/Home' + +document.addEventListener('DOMContentLoaded', () => { + const container = document.body.appendChild(document.createElement('div')); + const root = createRoot(container); + root.render(); +}) diff --git a/app/javascript/packs/hello_react.jsx b/app/javascript/packs/hello_react.jsx deleted file mode 100644 index 772fc97..0000000 --- a/app/javascript/packs/hello_react.jsx +++ /dev/null @@ -1,26 +0,0 @@ -// Run this example by adding <%= javascript_pack_tag 'hello_react' %> to the head of your layout file, -// like app/views/layouts/application.html.erb. All it does is render
Hello React
at the bottom -// of the page. - -import React from 'react' -import ReactDOM from 'react-dom' -import PropTypes from 'prop-types' - -const Hello = props => ( -
Hello {props.name}!
-) - -Hello.defaultProps = { - name: 'David' -} - -Hello.propTypes = { - name: PropTypes.string -} - -document.addEventListener('DOMContentLoaded', () => { - ReactDOM.render( - , - document.body.appendChild(document.createElement('div')), - ) -}) diff --git a/app/views/homepage/index.html.erb b/app/views/homepage/index.html.erb index 193609f..e69de29 100644 --- a/app/views/homepage/index.html.erb +++ b/app/views/homepage/index.html.erb @@ -1,2 +0,0 @@ -

Homepage#index

-

Find me in app/views/homepage/index.html.erb

diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a00d910..0567636 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -9,6 +9,7 @@ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> + <%= javascript_pack_tag 'Index' %> From c3ea033c4fc51227c7dba835d031c3309751d495 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Fri, 13 May 2022 12:39:21 -0400 Subject: [PATCH 7/9] temp: add example React component https://reactjs.org/docs/hooks-intro.html --- app/javascript/components/Home.jsx | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/app/javascript/components/Home.jsx b/app/javascript/components/Home.jsx index eaf9f66..484fa2a 100644 --- a/app/javascript/components/Home.jsx +++ b/app/javascript/components/Home.jsx @@ -1,10 +1,15 @@ -import React from "react"; +import React, { useState } from 'react'; -export default () => ( -
-

Hola mundo!

-

- Vamos a hacer una app con React. -

-
-); \ No newline at end of file +// https://reactjs.org/docs/hooks-intro.html +export default function () { + const [count, setCount] = useState(0); + + return ( +
+

You clicked {count} times

+ +
+ ); +} \ No newline at end of file From 9cf74325deccec0a1cf6747928aee22538836b65 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Thu, 12 May 2022 20:29:02 -0400 Subject: [PATCH 8/9] feat: implement local tasks component --- app/javascript/components/Home.jsx | 51 ++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/app/javascript/components/Home.jsx b/app/javascript/components/Home.jsx index 484fa2a..b53cdde 100644 --- a/app/javascript/components/Home.jsx +++ b/app/javascript/components/Home.jsx @@ -1,15 +1,46 @@ -import React, { useState } from 'react'; +import React, { useState } from "react"; -// https://reactjs.org/docs/hooks-intro.html -export default function () { - const [count, setCount] = useState(0); +export default () => { + const [tasks, setTasks] = useState([]); + const [inputValue, setInputValue] = useState(''); + + function addTask () { + const newTask = { + description: inputValue, + id: tasks.length + 1, + } + const newTasks = tasks.concat([newTask]); + setTasks(newTasks); + } + + function removeTask (id) { + const newTasks = tasks.filter((task) => ( + task.id !== id + )); + setTasks(newTasks); + } return ( -
-

You clicked {count} times

- +
+

Tareas

+ +
+

+ setInputValue(e.target.value)} /> + +
+ + { tasks.map((task) => ( +
+
+ +

+ { task.description } +

+
+ +
+ )) }
); -} \ No newline at end of file +}; From 2d110f92fb87b932dbd69942c609f95b71d087e7 Mon Sep 17 00:00:00 2001 From: Rafael Garin Date: Fri, 13 May 2022 09:54:20 -0400 Subject: [PATCH 9/9] feat: sync tasks with backend --- app/javascript/components/Home.jsx | 41 ++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/app/javascript/components/Home.jsx b/app/javascript/components/Home.jsx index b53cdde..448c0ce 100644 --- a/app/javascript/components/Home.jsx +++ b/app/javascript/components/Home.jsx @@ -1,25 +1,46 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; export default () => { const [tasks, setTasks] = useState([]); const [inputValue, setInputValue] = useState(''); - function addTask () { + async function addTask () { const newTask = { description: inputValue, - id: tasks.length + 1, } - const newTasks = tasks.concat([newTask]); - setTasks(newTasks); + const response = await fetch("/api/v1/tasks", { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(newTask), + }); + if (response.ok) { + loadTasks(); + } + } + + async function removeTask (id) { + const response = await fetch(`/api/v1/tasks/${id}`, { + method: 'DELETE', + }); + if (response.ok) { + loadTasks(); + } } - function removeTask (id) { - const newTasks = tasks.filter((task) => ( - task.id !== id - )); - setTasks(newTasks); + async function loadTasks () { + const response = await fetch("/api/v1/tasks") + if (response.ok) { + const jsonResponse = await response.json(); + setTasks(jsonResponse); + } } + useEffect(() => { + loadTasks(); + }, []); + return (

Tareas