Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution for beehiiv Coding Challenge #1

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ gem "pg", "~> 1.1"
gem "puma", "~> 5.0"
gem "rack-cors"
gem "bootsnap", ">= 1.4.4", require: false
gem "email_validator"

group :development, :test do
gem "debug"
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ GEM
irb (>= 1.5.0)
reline (>= 0.3.1)
diff-lcs (1.5.0)
email_validator (2.2.4)
activemodel
erubi (1.12.0)
factory_bot (6.2.0)
activesupport (>= 5.0.0)
Expand Down Expand Up @@ -126,6 +128,8 @@ GEM
nio4r (2.5.8)
nokogiri (1.14.1-arm64-darwin)
racc (~> 1.4)
nokogiri (1.14.1-x86_64-linux)
racc (~> 1.4)
parallel (1.22.1)
parser (3.2.0.0)
ast (~> 2.4.1)
Expand Down Expand Up @@ -238,13 +242,15 @@ GEM
PLATFORMS
arm64-darwin-21
arm64-darwin-22
x86_64-linux

DEPENDENCIES
bootsnap (>= 1.4.4)
bundler
database_cleaner-active_record
database_cleaner-redis
debug
email_validator
factory_bot
foreman
listen (~> 3.3)
Expand Down
3 changes: 2 additions & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
web: bundle exec puma -w ${WEB_CONCURRENCY:-3} -p ${PORT:-2000} -e ${RACK_ENV:-development} -C ./config/puma.rb
web: bundle exec rails s
release: bin/rake db:migrate
2 changes: 2 additions & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: PORT=2001 yarn --cwd frontend start
api: PORT=2000 bundle exec rails s
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ Challenge is a rails/react app meant to be used with our code challenge assignme
### Update Subscriber Status Modal

![image](https://user-images.githubusercontent.com/5751986/148653182-3a282533-dbb8-4d96-a511-5a5008cf3daf.png)

### Use this page as a walkthrough to prep this app to run on Heroku

https://medium.com/swlh/set-up-your-rails-and-react-apps-for-heroku-right-from-the-start-eed2bca83b6
56 changes: 15 additions & 41 deletions app/controllers/subscribers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,30 @@ class SubscribersController < ApplicationController
##
# GET /api/subscribers
def index
subscribers = [
{
id: 1,
name: "Rick Sanchez",
email: "[email protected]",
status: "active"
},
{
id: 2,
name: "Morty Smith",
email: "[email protected]",
status: "inactive"
},
{
id: 3,
name: "Jerry Smith",
email: "[email protected]",
status: "active"
},
{
id: 4,
name: "Beth Smith",
email: "[email protected]",
status: "active"
},
{
id: 5,
name: "Summer Smith",
email: "[email protected]",
status: "active"
},
{
id: 6,
name: "Bird Person",
email: "[email protected]",
status: "active"
}
]

total_records = subscribers.count
limited_subscribers = subscribers[offset..limit]
total_records = Subscriber.count
limited_subscribers = Subscriber.limit(limit).offset(offset)

render json: {subscribers: limited_subscribers, pagination: pagination(total_records)}, formats: :json
end

##
# POST /api/subscribers
def create
subscriber = Subscriber.new(name: params[:name], email: params[:email], status: "active")
subscriber.save!
render json: {message: "Subscriber created successfully"}, formats: :json, status: :created
rescue ActiveRecord::RecordInvalid => error
render json: {message: "Subscriber not created: #{error.message}"}, formats: :json, status: :forbidden
end

##
# PATCH /api/subscribers/:id
def update
subscriber = Subscriber.find(params[:id])
subscriber.status = params[:status]
subscriber.save!
render json: {message: "Subscriber updated successfully"}, formats: :json, status: :ok
rescue ActiveRecord::RecordNotFound => error
render json: {message: "Subscriber not updated successfully: #{error.message}"}, formats: :json, status: :not_found
end
end
7 changes: 7 additions & 0 deletions app/models/subscriber.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Subscriber < ApplicationRecord
default_scope { order(id: :asc) }
validates :name, presence: true
validates :email, presence: true, email: true
validates_uniqueness_of :email, :case_sensitive => false
validates :status, :inclusion => { :in => %w{active inactive} }
end
2 changes: 2 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function App() {

const onSuccessAddSubscriber = () => {
setShowAddModal(false)
refreshSubscribers()
}

const onUpdateStatusSelectected = (subscriberId, status) => {
Expand All @@ -87,6 +88,7 @@ function App() {
const onSuccessUpdateStatusSubscriber = () => {
setFocusedSubscriberId('')
setFocusedSubscriberStatus('')
refreshSubscribers()
}

return (
Expand Down
16 changes: 13 additions & 3 deletions client/src/components/AddSubscriberModal/AddSubscriberModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const AddSubscriberModal = (props) => {
const [isSaving, setIsSaving] = useState(false)
const [email, setEmail] = useState('')
const [name, setName] = useState('')
const [error, setError] = useState(false)

const handleChange = (e) => {
const { target: { name, value }} = e
Expand All @@ -26,23 +27,32 @@ const AddSubscriberModal = (props) => {
name
}

setError(false)
setIsSaving(true)
createSubscriber(payload)
.then(() => {
onSuccess()
onCloseForm()
})
.catch((payload) => {
const error = payload?.response?.data?.message || 'Something went wrong'
console.error(error)
setError(error)
})
.finally(() => {
setIsSaving(false)
})
}
const onCloseForm = () => {
setError(false)
setEmail('')
setName('')
onClose()
}

return (
<Modal modalTitle="Add Subscriber" showModal={isOpen} onCloseModal={onClose}>
<Modal modalTitle="Add Subscriber" showModal={isOpen} onCloseModal={onCloseForm}>
<>
{error && <div className="p-6" style={{color: 'red'}}>{error}</div>}
<ModalBody>
<form className="my-4 text-blueGray-500 text-lg leading-relaxed">
<div className="mb-4">
Expand Down Expand Up @@ -77,7 +87,7 @@ const AddSubscriberModal = (props) => {
<SecondaryButton
className="background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1"
type="button"
onClick={onClose}
onClick={onCloseForm}
>
Cancel
</SecondaryButton>
Expand Down
2 changes: 1 addition & 1 deletion config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require_relative "config/environment"
Rails.application.load_server

use Rack::Auth::Basic, "Restricted Area" do |username, password|
username == "username" && password == "password"
username == ENV.fetch("USERNAME") && password == ENV.fetch("PASSWORD")
end

app = Rack::Builder.new {
Expand Down
11 changes: 11 additions & 0 deletions db/migrate/20230806163344_create_subscribers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateSubscribers < ActiveRecord::Migration[6.1]
def change
create_table :subscribers do |t|
t.string :name
t.string :email
t.string :status

t.timestamps
end
end
end
10 changes: 9 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)

# Create 127 subscribers

for subscriber_count in 1..127 do
Subscriber.create(name: "Test Guy#{subscriber_count}", email: "tguy#{subscriber_count}@test.com", status: (subscriber_count % 4 == 0) ? "inactive" : "active")
end
7 changes: 7 additions & 0 deletions lib/tasks/start.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace :start do
task :development do
exec 'heroku local -f Procfile.dev'
end
end
desc 'Start development server'
task :start => 'start:development'
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
},
"scripts": {
"postinstall": "cd client && yarn",
"heroku-postbuild": "npm run build",
"build": "npm run --prefix client build",
"deploy": "git fetch && git push -f heroku origin/master:refs/heads/master",
"heroku-postbuild": "yarn build && yarn deploy",
"build": "yarn --cwd client install && yarn --cwd client build",
"deploy": "cp -a client/build/. public/",
"start": "npm run build && npm run start:server",
"start:server": "bundle exec foreman start",
"test": "npm run --prefix client build",
Expand Down
Loading