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

Alan challenge Submission #19

Open
wants to merge 9 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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@
/config/master.key

# Ignore Node Modules
/node_modules
/node_modules

.env
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.1.2
3.3.4
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.1.2"
ruby "3.3.4"

gem "rails", "~> 6.1"
gem "pg", "~> 1.1"
Expand Down
11 changes: 7 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ GEM
marcel (1.0.2)
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.8.7)
minitest (5.17.0)
mocha (1.13.0)
msgpack (1.4.2)
msgpack (1.7.2)
net-imap (0.3.4)
date
net-protocol
Expand All @@ -124,12 +125,13 @@ GEM
net-smtp (0.3.3)
net-protocol
nio4r (2.5.8)
nokogiri (1.14.1-arm64-darwin)
nokogiri (1.14.1)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
parallel (1.22.1)
parser (3.2.0.0)
ast (~> 2.4.1)
pg (1.2.3)
pg (1.3.0)
public_suffix (4.0.6)
puma (5.5.2)
nio4r (~> 2.0)
Expand Down Expand Up @@ -238,6 +240,7 @@ GEM
PLATFORMS
arm64-darwin-21
arm64-darwin-22
arm64-darwin-23

DEPENDENCIES
bootsnap (>= 1.4.4)
Expand All @@ -262,7 +265,7 @@ DEPENDENCIES
webmock (~> 3.5.0)

RUBY VERSION
ruby 3.1.2p20
ruby 3.3.4p94

BUNDLED WITH
2.4.5
4 changes: 2 additions & 2 deletions app/controllers/concerns/pagination_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ def page
end

def limit
return 100 if params[:per_page].nil?
return 5 if params[:per_page].nil?

(params[:per_page].to_i > 100) ? 100 : params[:per_page].to_i
(params[:per_page].to_i > 5) ? 10 : params[:per_page].to_i
end

def offset
Expand Down
59 changes: 17 additions & 42 deletions app/controllers/subscribers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,31 @@ 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"
}
]

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

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

def create
render json: {message: "Subscriber created successfully"}, formats: :json, status: :created
subscriber = Subscriber.create(email: params[:email], name: params[:name], status: "active")
if subscriber.save
render json: {message: "Subscriber created successfully"}, formats: :json, status: :created
else
render json: {message: "Error: Failed to subscribe!"}, formats: :json, status: :unprocessable_entity
end
end

def update
render json: {message: "Subscriber updated successfully"}, formats: :json, status: :ok
subscriber = Subscriber.find(params[:id])

updated_status = (subscriber.status == "active") ? "inactive" : "active"

if subscriber.update({status: updated_status})
render json: {message: "Subscriber updated successfully"}, formats: :json, status: :ok
else
render json: {message: "Error: Failed to update subscriber!"}, formats: :json, status: :unprocessable_entity
end
end
end
13 changes: 13 additions & 0 deletions app/models/subscriber.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Subscriber < ApplicationRecord
before_validation :formatEmail

validates :name, presence: true
validates :email, presence: true, uniqueness: {case_sensitive: false}, format: {with: URI::MailTo::EMAIL_REGEXP}
validates :status, presence: true, inclusion: ["active", "inactive"]

private

def formatEmail
self.email = email.downcase.strip if email.present?
end
end
35 changes: 19 additions & 16 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ function App() {
);
const [perPage] = useQueryParam(
'perPage',
withDefault(NumberParam, 25)
withDefault(NumberParam, 10)
);
const [showAddModal, setShowAddModal] = useState(false)
const [focusedSubscriberId, setFocusedSubscriberId] = useState('')
const [focusedSubscriberStatus, setFocusedSubscriberStatus] = useState('')
const [subscribers, setSubscribers] = useState([])
const [pagination, setPagination] = useState({})
const [isLoading, setIsLoading] = useState(false)
const [updatedList, setUpdatedList] = useState(false)

const refreshSubscribers = useCallback(() => {
const params = {
Expand All @@ -38,25 +39,25 @@ function App() {

setIsLoading(true)
getSubscribers(params)
.then((payload) => {
const subscribers = payload?.data?.subscribers || []
const pagination = payload?.data?.pagination || {}

setSubscribers(subscribers)
setPagination(pagination)
})
.catch((payload) => {
const error = payload?.response?.data?.message || 'Something went wrong'
console.error(error)
})
.finally(() => {
setIsLoading(false)
})
.then((payload) => {
const subscribers = payload?.data?.subscribers || []
const pagination = payload?.data?.pagination || {}

setSubscribers(subscribers)
setPagination(pagination)
})
.catch((payload) => {
const error = payload?.response?.data?.message || 'Something went wrong'
alert(error)
})
.finally(() => {
setIsLoading(false)
})
}, [page, perPage]);

useEffect(() => {
refreshSubscribers()
}, [refreshSubscribers]);
}, [refreshSubscribers, updatedList]);

const onPageSelected = (page) => {
setPage(page)
Expand All @@ -71,6 +72,7 @@ function App() {
}

const onSuccessAddSubscriber = () => {
setUpdatedList(!updatedList)
setShowAddModal(false)
}

Expand All @@ -85,6 +87,7 @@ function App() {
}

const onSuccessUpdateStatusSubscriber = () => {
setUpdatedList(!updatedList)
setFocusedSubscriberId('')
setFocusedSubscriberStatus('')
}
Expand Down
24 changes: 12 additions & 12 deletions client/src/components/AddSubscriberModal/AddSubscriberModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const AddSubscriberModal = (props) => {
const [name, setName] = useState('')

const handleChange = (e) => {
const { target: { name, value }} = e
const { target: { name, value } } = e

if (name === 'email') {
setEmail(value)
Expand All @@ -28,16 +28,16 @@ const AddSubscriberModal = (props) => {

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

return (
Expand Down Expand Up @@ -96,7 +96,7 @@ const AddSubscriberModal = (props) => {
}

AddSubscriberModal.propTypes = {
isOpen: PropTypes.bool,
isOpen: PropTypes.bool,
onClose: PropTypes.func,
onSuccess: PropTypes.func
}
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["USERNAME"] && password == ENV["PASSWORD"]
end

app = Rack::Builder.new {
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20240827022218_create.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Create < ActiveRecord::Migration[6.1]
def change
create_table :subscribers do |s|
s.string :name, null: false
s.string :email, null: false, unique: true
s.string :status, null: false, default: "active"
s.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.

37 changes: 37 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,40 @@
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)
#
subscriber_list = [
{
name: "Rick Sanchez",
email: "[email protected]",
status: "active"
},
{
name: "Morty Smith",
email: "[email protected]",
status: "inactive"
},
{
name: "Jerry Smith",
email: "[email protected]",
status: "active"
},
{
name: "Beth Smith",
email: "[email protected]",
status: "active"
},
{
name: "Summer Smith",
email: "[email protected]",
status: "active"
},
{
name: "Bird Person",
email: "[email protected]",
status: "active"
}
]

subscriber_list.each do |subscriber|
Subscriber.create!(email: subscriber[:email], name: subscriber[:name], status: subscriber[:status])
end