Skip to content

Commit

Permalink
Merge pull request #107 from debtcollective/feat/cancel-active-subscr…
Browse files Browse the repository at this point in the history
…iption

Feat/cancel active subscription
  • Loading branch information
castrolem authored Oct 16, 2019
2 parents 4fff9d4 + baf3951 commit 9fe9f36
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 24 deletions.
2 changes: 2 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class ApplicationController < ActionController::Base
protect_from_forgery unless: -> { request.format.json? }

helper_method :current_user, :logged_in?

def current_user
Expand Down
1 change: 1 addition & 0 deletions app/controllers/static_pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class StaticPagesController < ApplicationController
def home
@current_user = current_user
@current_user_subscription = @current_user&.active_subscription
@plans = Plan.all.order('amount asc')
end
end
1 change: 1 addition & 0 deletions app/controllers/subscription_charges_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def create
)

if charge
@subscription.active = true
@subscription.last_charge_at = DateTime.now
@subscription.save

Expand Down
26 changes: 26 additions & 0 deletions app/controllers/subscriptions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

class SubscriptionsController < ApplicationController
before_action :set_user, only: %i[destroy]

# DELETE /user/:user_id/subscription
# DELETE /user/:user_id/subscription.json
def destroy
head :not_authorized unless current_user == @user

subscription = @user.active_subscription

subscription.active = false
if subscription.save
head :ok
else
head :bad_request
end
end

private

def set_user
@user = User.find(params[:user_id])
end
end
79 changes: 79 additions & 0 deletions app/javascript/bundles/User/components/SubscriptionCancel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useState } from 'react'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'

const SUBSCRIPTION_CANCEL_URL = userID => `/users/${userID}/subscription`

function SubscriptionCancelView ({ user, subscription }) {
const [open, setOpen] = useState(false)
const [active, toggleActive] = useState(subscription.active)

const handleClickOpen = () => {
setOpen(true)
}

const handleClose = () => {
setOpen(false)
}

const handleSubscriptionCancellation = async () => {
const isSubscriptionCancelled = await fetch(
SUBSCRIPTION_CANCEL_URL(user.id),
{
method: 'delete'
}
)

toggleActive(!subscription.active)

handleClose()
}

if (!subscription.active) {
return null
}

return (
<div>
<Button color='secondary' onClick={handleClickOpen}>
Cancel Subscription
</Button>
{!active && 'No active subscription'}
<Dialog
open={open}
onClose={handleClose}
id='cancel-subscription-dialog'
aria-labelledby='cancel-subscription-title'
aria-describedby='cancel-subscription-description'
>
<DialogTitle id='cancel-subscription-title'>
Do you want to terminate your current subscription?
</DialogTitle>
<DialogContent>
<DialogContentText id='cancel-subscription-description'>
Terminating your subscription will stop your current plan and the
benefits you receive from it.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color='primary'>
Close
</Button>
<Button
onClick={handleSubscriptionCancellation}
color='primary'
autoFocus
>
Cancel Subscription
</Button>
</DialogActions>
</Dialog>
</div>
)
}

export const SubscriptionCancel = props => <SubscriptionCancelView {...props} />
29 changes: 15 additions & 14 deletions app/javascript/bundles/User/components/UserShow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,25 @@ function UserShowView ({ user, subscription, streak }) {
const classes = useStyles()

return (
<Paper className={classes.root}>
<h3>Contact Data</h3>
<p>
<strong>Name:</strong>
</p>
<p>{user.name}</p>

<p>
<strong>Email:</strong>
</p>
<p>{user.email}</p>

{subscription && streak && (
<>
{subscription && subscription.active && streak && (
<p className='notice--subscription'>
You have been subscribed for {streak}
</p>
)}
</Paper>
<Paper className={classes.root}>
<h3>Contact Data</h3>
<p>
<strong>Name:</strong>
</p>
<p>{user.name}</p>

<p>
<strong>Email:</strong>
</p>
<p>{user.email}</p>
</Paper>
</>
)
}

Expand Down
4 changes: 3 additions & 1 deletion app/javascript/packs/user-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import ReactOnRails from 'react-on-rails'

import { UserShow } from '../bundles/User/components/UserShow'
import { DonationsHistory } from '../bundles/User/components/DonationsHistory'
import { SubscriptionCancel } from '../bundles/User/components/SubscriptionCancel'

ReactOnRails.register({
UserShow,
DonationsHistory
DonationsHistory,
SubscriptionCancel
})
2 changes: 1 addition & 1 deletion app/jobs/find_overdue_subscriptions_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class FindOverdueSubscriptionsJob < ApplicationJob
queue_as :default

def perform
subscriptions_to_charge = Subscription.active.select do |subscription|
subscriptions_to_charge = Subscription.where(active: true).select do |subscription|
# create charge if there's no last_charge_at date, meaning it would be the
# first time we attempt to charge this customer this subscription.
subscription.last_charge_at ? subscription.last_charge_at <= 30.days.ago : true
Expand Down
2 changes: 1 addition & 1 deletion app/models/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Subscription < ApplicationRecord
validates :plan_id, presence: true
validates :user_id, uniqueness: { scope: %i[plan_id active] }, if: :user?

scope :active, -> { where(active: true) }
scope :active, -> { where(active: true).first }

def user?
!user_id.blank?
Expand Down
10 changes: 7 additions & 3 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class User < ApplicationRecord

SSO_ATTRIBUTES = %w[admin avatar_url banned custom_fields email name username].freeze

has_one :subscription
has_many :subscriptions
has_many :cards
has_many :donations

Expand All @@ -32,10 +32,14 @@ def admin?
end

def current_streak
return 'Currently, you don\'t own an active subscribption' unless subscription
return 'Currently, you don\'t own an active subscription' unless active_subscription

start_date ||= subscription.start_date
start_date ||= active_subscription.start_date

time_ago_in_words(start_date)
end

def active_subscription
subscriptions.active unless subscriptions.active.blank?
end
end
6 changes: 5 additions & 1 deletion app/views/static_pages/home.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
</h3>
<h4><%= plan.headline %></h4>
<%= plan.description %>
<p><%= link_to 'Subscribe', @current_user ? new_subscription_charge_path(plan_id: plan) : login_path %></p>
<% if @current_user_subscription&.plan&.id == plan.id %>
<p>Subscribed</p>
<% else %>
<p><%= link_to 'Subscribe', @current_user ? new_subscription_charge_path(plan_id: plan) : login_path %></p>
<% end %>
</div>
<% end %>
<div class="subscription--plan" id="one-time-donation">
Expand Down
5 changes: 3 additions & 2 deletions app/views/users/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<section class="section-content">
<p id="notice"><%= notice %></p>

<%= react_component("UserShow", props: {user: @user, streak: @user.current_streak, subscription: @user.subscription}) %>
<%= react_component("DonationsHistory", props: {activePlan: @user.subscription&.plan, donations: @user.donations}) %>
<%= react_component("UserShow", props: {user: @user, streak: @user.current_streak, subscription: @user.active_subscription}) %>
<%= react_component("DonationsHistory", props: {activePlan: @user.active_subscription&.plan, donations: @user.donations}) %>
<%= react_component("SubscriptionCancel", props: {user: @user, subscription: @user.active_subscription}) %>
</section>
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
resources :users, only: %i[show new edit update create destroy] do
resource :streak, only: %i[show]
resources :cards, only: %i[index destroy]
resource :subscription, only: %i[destroy]
end

get '/login' => 'sessions#login'
Expand Down
1 change: 1 addition & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
t.uuid "donation_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.uuid "user_id"
t.index ["donation_id"], name: "index_subscription_donations_on_donation_id"
t.index ["subscription_id", "donation_id"], name: "index_subscription_donations_on_subscription_id_and_donation_id", unique: true
t.index ["subscription_id"], name: "index_subscription_donations_on_subscription_id"
Expand Down
22 changes: 21 additions & 1 deletion spec/features/user/users_profile_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
describe 'User - manages their profile', type: :feature, js: true do
describe 'home' do
let!(:user) { FactoryBot.create(:user) }
let!(:subscription) { FactoryBot.create(:subscription, user_id: user.id) }
let!(:subscription) { FactoryBot.create(:subscription, user_id: user.id, active: true) }
let!(:one_time_donations) { FactoryBot.create_list(:donation, 5, user_id: user.id, donation_type: Donation::DONATION_TYPES[:one_off]) }

before(:each) do
Expand All @@ -27,5 +27,25 @@
expect(page).to have_content(donation.amount)
end
end

it 'can cancel an active subscription' do
expect(subscription.active).to eq(true)
visit user_path(user)
expect(page).to have_content(user.name)
expect(page).to have_content(user.email)

expect(page).to have_content(subscription.plan.name)

click_button 'Cancel Subscription'

expect(page).to have_content('Do you want to terminate your current subscription?')
within '#cancel-subscription-dialog' do
click_button 'Cancel Subscription'
end

expect(page).to have_content('No active subscription')
subscription.reload
expect(subscription.active).to eq(false)
end
end
end

0 comments on commit 9fe9f36

Please sign in to comment.