diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 55205328..50933fd1 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,18 +1,38 @@ # frozen_string_literal: true class UsersController < ApplicationController - before_action :set_user, only: %i[show] + layout 'backoffice' + before_action :set_user + before_action :verify_current_user # GET /users/1 # GET /users/1.json def show - redirect_to root_path unless current_user == @user + current_page_title('Your dashboard') + end + + # pages + def subscription + current_page_title('Subscription management') @is_subscription_changing = UserPlanChange.where(user_id: @user.id, status: 'pending').first end + def donation_history + current_page_title('Donation history') + end + private + def current_page_title(page_title) + @current_page_title ||= page_title + end + + def verify_current_user + redirect_to root_path unless current_user == @user + end + def set_user - @user = User.find(params[:id]) + user_param_id = params[:id] || params[:user_id] + @user = User.find(user_param_id) end end diff --git a/app/javascript/bundles/User/components/Drawer.jsx b/app/javascript/bundles/User/components/Drawer.jsx new file mode 100644 index 00000000..7bd74afe --- /dev/null +++ b/app/javascript/bundles/User/components/Drawer.jsx @@ -0,0 +1,159 @@ +import React from 'react' +import PropTypes from 'prop-types' +import AppBar from '@material-ui/core/AppBar' +import CssBaseline from '@material-ui/core/CssBaseline' +import Divider from '@material-ui/core/Divider' +import Drawer from '@material-ui/core/Drawer' +import Hidden from '@material-ui/core/Hidden' +import IconButton from '@material-ui/core/IconButton' +import List from '@material-ui/core/List' +import ListItem from '@material-ui/core/ListItem' +import ListItemIcon from '@material-ui/core/ListItemIcon' +import ListItemText from '@material-ui/core/ListItemText' +import UsersIcon from '@material-ui/icons/SupervisedUserCircle' +import BookIcon from '@material-ui/icons/Book' +import SubscriptionsIcon from '@material-ui/icons/Subscriptions' +import MenuIcon from '@material-ui/icons/Menu' +import Toolbar from '@material-ui/core/Toolbar' +import Typography from '@material-ui/core/Typography' +import { makeStyles, useTheme } from '@material-ui/core/styles' + +const drawerWidth = 240 + +const useStyles = makeStyles(theme => ({ + root: { + display: 'flex' + }, + drawer: { + [theme.breakpoints.up('sm')]: { + width: drawerWidth, + flexShrink: 0 + } + }, + appBar: { + marginLeft: drawerWidth, + [theme.breakpoints.up('sm')]: { + width: `calc(100% - ${drawerWidth}px)` + } + }, + menuButton: { + marginRight: theme.spacing(2), + [theme.breakpoints.up('sm')]: { + display: 'none' + } + }, + toolbar: theme.mixins.toolbar, + drawerPaper: { + width: drawerWidth + }, + content: { + flexGrow: 1, + padding: theme.spacing(3) + } +})) + +function ResponsiveDrawer (props) { + const { container } = props + const classes = useStyles() + const theme = useTheme() + const [mobileOpen, setMobileOpen] = React.useState(false) + + function handleDrawerToggle () { + setMobileOpen(!mobileOpen) + } + + const drawer = ( +
+
+ + + + + + + + + + + + + + + + + + + + + +
+ ) + + return ( +
+ + + + + + + + {props.pageTitle} + + + + +
+ ) +} + +ResponsiveDrawer.propTypes = { + pageTitle: PropTypes.string.isRequired, + user: PropTypes.object.isRequired +} + +export default props => diff --git a/app/javascript/packs/user-bundle.js b/app/javascript/packs/user-bundle.js index d43bcb42..81873eba 100644 --- a/app/javascript/packs/user-bundle.js +++ b/app/javascript/packs/user-bundle.js @@ -4,10 +4,12 @@ import { UserShow } from '../bundles/User/components/UserShow' import { DonationsHistory } from '../bundles/User/components/DonationsHistory' import { SubscriptionCancel } from '../bundles/User/components/SubscriptionCancel' import { CurrentPlan } from '../bundles/User/components/CurrentPlan' +import Drawer from '../bundles/User/components/Drawer' ReactOnRails.register({ UserShow, DonationsHistory, SubscriptionCancel, - CurrentPlan + CurrentPlan, + Drawer }) diff --git a/app/views/layouts/backoffice.html.erb b/app/views/layouts/backoffice.html.erb new file mode 100644 index 00000000..60c477f0 --- /dev/null +++ b/app/views/layouts/backoffice.html.erb @@ -0,0 +1,35 @@ + + + + Fundraising + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + <%= content_for?(:head) ? yield(:head) : '' %> + + <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> + + <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> + <%= javascript_include_tag 'https://checkout.stripe.com/checkout.js' %> + <%= javascript_include_tag 'https://js.stripe.com/v3/' %> + <%= javascript_pack_tag 'user-bundle' %> + + + + + + + + + + + + + <%= react_component("Drawer", props: {pageTitle: @current_page_title, user: @user}) %> +
+
+ <%= yield %> +
+
+ + diff --git a/app/views/users/donation_history.html.erb b/app/views/users/donation_history.html.erb new file mode 100644 index 00000000..bd79940b --- /dev/null +++ b/app/views/users/donation_history.html.erb @@ -0,0 +1,5 @@ +
+

<%= notice %>

+ + <%= react_component("DonationsHistory", props: {donations: @user.donations}) %> +
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 9701ea85..2a544ce2 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -2,6 +2,4 @@

<%= notice %>

<%= react_component("UserShow", props: {user: @user, streak: @user.current_streak, subscription: @user.active_subscription}) %> - <%= react_component("SubscriptionCancel", props: {user: @user, subscription: @user.active_subscription, activePlan: @user.active_subscription&.plan, isSubscriptionChanging: @is_subscription_changing}) %> - <%= react_component("DonationsHistory", props: {donations: @user.donations}) %> diff --git a/app/views/users/subscription.html.erb b/app/views/users/subscription.html.erb new file mode 100644 index 00000000..ec5e6384 --- /dev/null +++ b/app/views/users/subscription.html.erb @@ -0,0 +1,5 @@ +
+

<%= notice %>

+ + <%= react_component("SubscriptionCancel", props: {user: @user, subscription: @user.active_subscription, activePlan: @user.active_subscription&.plan, isSubscriptionChanging: @is_subscription_changing}) %> +
diff --git a/config/routes.rb b/config/routes.rb index 66aade7d..dc59b876 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,6 +19,8 @@ end resources :users, only: %i[show new edit update create destroy] do + get '/subscription' => 'users#subscription', as: :current_subscription + get '/donations' => 'users#donation_history', as: :latest_donations resource :streak, only: %i[show] resources :cards, only: %i[index destroy] resource :subscription, only: %i[destroy] diff --git a/spec/features/plan_change_spec.rb b/spec/features/plan_change_spec.rb index 42f8175c..6924f08c 100644 --- a/spec/features/plan_change_spec.rb +++ b/spec/features/plan_change_spec.rb @@ -16,6 +16,9 @@ within '#contact-data' do expect(page).to have_content(user.name) end + + visit user_current_subscription_path(user) + expect(page).to have_content("You're subscribed") click_link 'Change Subscription' diff --git a/spec/features/user/users_profile_spec.rb b/spec/features/user/users_profile_spec.rb index 7d983b18..d606f6d1 100644 --- a/spec/features/user/users_profile_spec.rb +++ b/spec/features/user/users_profile_spec.rb @@ -3,49 +3,43 @@ require 'rails_helper' 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, active: true) } - let!(:one_time_donations) { FactoryBot.create_list(:donation, 5, user_id: user.id, donation_type: Donation::DONATION_TYPES[:one_off]) } + let!(:user) { FactoryBot.create(:user) } + 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 - allow_any_instance_of(SessionProvider).to receive(:current_user).and_return(user) - end - - it 'can view their subscription and donation history' do - 5.times do - donation = FactoryBot.create(:donation, user_id: user.id) - FactoryBot.create(:subscription_donation, subscription_id: subscription.id, donation_id: donation.id) - end - 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) + before(:each) do + allow_any_instance_of(SessionProvider).to receive(:current_user).and_return(user) + end - user.donations.each do |donation| - expect(page).to have_content(donation.amount) - end + it 'can view their subscription and donation history' do + 5.times do + donation = FactoryBot.create(:donation, user_id: user.id) + FactoryBot.create(:subscription_donation, subscription_id: subscription.id, donation_id: donation.id) end + visit user_latest_donations_path(user) + expect(page).to have_content('Your Donations History') - 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) + user.donations.each do |donation| + expect(page).to have_content(donation.amount) + end + end - expect(page).to have_content(subscription.plan.name) + it 'can cancel an active subscription' do + expect(subscription.active).to eq(true) + visit user_current_subscription_path(user) + expect(page).to have_content("You're subscribed") - click_button 'Cancel Subscription' + expect(page).to have_content(subscription.plan.name) - expect(page).to have_content('Do you want to terminate your current subscription?') - within '#cancel-subscription-dialog' do - click_button 'Cancel Subscription' - end + click_button 'Cancel Subscription' - expect(page).to have_content('No active subscription') - subscription.reload - expect(subscription.active).to eq(false) + 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