mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
WIP: payment schedules dashboard
This commit is contained in:
parent
d767cf5f85
commit
16bb4bc76d
@ -6,6 +6,15 @@ class API::PaymentSchedulesController < API::ApiController
|
||||
before_action :set_payment_schedule, only: %i[download cancel]
|
||||
before_action :set_payment_schedule_item, only: %i[cash_check refresh_item pay_item]
|
||||
|
||||
def index
|
||||
@payment_schedules = PaymentSchedule.where('invoicing_profile_id = ?', current_user.invoicing_profile.id)
|
||||
.includes(:invoicing_profile, :payment_schedule_items, :subscription)
|
||||
.joins(:invoicing_profile)
|
||||
.order('payment_schedules.created_at DESC')
|
||||
.page(params[:page])
|
||||
.per(params[:size])
|
||||
end
|
||||
|
||||
def list
|
||||
authorize PaymentSchedule
|
||||
|
||||
|
@ -14,6 +14,11 @@ export default class PaymentScheduleAPI {
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
async index (query: PaymentScheduleIndexRequest): Promise<Array<PaymentSchedule>> {
|
||||
const res: AxiosResponse = await apiClient.get(`/api/payment_schedules?page=${query.query.page}&size=${query.query.size}`);
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
async cashCheck(paymentScheduleItemId: number): Promise<CashCheckResponse> {
|
||||
const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/items/${paymentScheduleItemId}/cash_check`);
|
||||
return res?.data;
|
||||
@ -38,5 +43,10 @@ export default class PaymentScheduleAPI {
|
||||
const api = new PaymentScheduleAPI();
|
||||
return wrapPromise(api.list(query));
|
||||
}
|
||||
|
||||
static index(query: PaymentScheduleIndexRequest): IWrapPromise<Array<PaymentSchedule>> {
|
||||
const api = new PaymentScheduleAPI();
|
||||
return wrapPromise(api.index(query));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices
|
||||
* for the currentUser
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { IApplication } from '../models/application';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Loader } from './loader';
|
||||
import { react2angular } from 'react2angular';
|
||||
import PaymentScheduleAPI from '../api/payment-schedule';
|
||||
import { PaymentSchedulesTable } from './payment-schedules-table';
|
||||
import { FabButton } from './fab-button';
|
||||
import { User } from '../models/user';
|
||||
|
||||
declare var Application: IApplication;
|
||||
|
||||
interface PaymentSchedulesDashboardProps {
|
||||
currentUser: User
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
const paymentSchedulesIndex = PaymentScheduleAPI.index({ query: { page: 1, size: PAGE_SIZE } });
|
||||
|
||||
const PaymentSchedulesDashboard: React.FC<PaymentSchedulesDashboardProps> = ({ currentUser }) => {
|
||||
const { t } = useTranslation('logged');
|
||||
|
||||
const [paymentSchedules, setPaymentSchedules] = useState(paymentSchedulesIndex.read());
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
|
||||
/**
|
||||
* Fetch from the API the next payment schedules to display, for the current filters, and append them to the current results table.
|
||||
*/
|
||||
const handleLoadMore = (): void => {
|
||||
setPageNumber(pageNumber + 1);
|
||||
|
||||
const api = new PaymentScheduleAPI();
|
||||
api.index({ query: { page: pageNumber + 1, size: PAGE_SIZE }}).then((res) => {
|
||||
const list = paymentSchedules.concat(res);
|
||||
setPaymentSchedules(list);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload from te API all the currently displayed payment schedules
|
||||
*/
|
||||
const handleRefreshList = (): void => {
|
||||
const api = new PaymentScheduleAPI();
|
||||
api.index({ query: { page: 1, size: PAGE_SIZE * pageNumber }}).then((res) => {
|
||||
setPaymentSchedules(res);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current collection of payment schedules is empty or not.
|
||||
*/
|
||||
const hasSchedules = (): boolean => {
|
||||
return paymentSchedules.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are some results for the current filters that aren't currently shown.
|
||||
*/
|
||||
const hasMoreSchedules = (): boolean => {
|
||||
return hasSchedules() && paymentSchedules.length < paymentSchedules[0].max_length;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="payment-schedules-dashboard">
|
||||
{!hasSchedules() && <div>{t('app.admin.invoices.payment_schedules.no_payment_schedules')}</div>}
|
||||
{hasSchedules() && <div className="schedules-list">
|
||||
<PaymentSchedulesTable paymentSchedules={paymentSchedules} showCustomer={false} refreshList={handleRefreshList} operator={currentUser} />
|
||||
{hasMoreSchedules() && <FabButton className="load-more" onClick={handleLoadMore}>{t('app.admin.invoices.payment_schedules.load_more')}</FabButton>}
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const PaymentSchedulesDashboardWrapper: React.FC<PaymentSchedulesDashboardProps> = ({ currentUser }) => {
|
||||
return (
|
||||
<Loader>
|
||||
<PaymentSchedulesDashboard currentUser={currentUser} />
|
||||
</Loader>
|
||||
);
|
||||
}
|
||||
|
||||
Application.Components.component('paymentSchedulesDashboard', react2angular(PaymentSchedulesDashboardWrapper, ['currentUser']));
|
@ -20,7 +20,7 @@ interface PaymentSchedulesListProps {
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
const paymentSchedulesList = PaymentScheduleAPI.list({ query: { page: 1, size: 20 } });
|
||||
const paymentSchedulesList = PaymentScheduleAPI.list({ query: { page: 1, size: PAGE_SIZE } });
|
||||
|
||||
const PaymentSchedulesList: React.FC<PaymentSchedulesListProps> = ({ currentUser }) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
@ -30,13 +30,13 @@ Application.Controllers.controller('DashboardController', ['$scope', 'memberProm
|
||||
const initialize = () => $scope.social.networks = filterNetworks();
|
||||
|
||||
/**
|
||||
* Filter social network or website that are associated with the profile of the user provided in promise
|
||||
* Filter the social networks or websites that are associated with the profile of the user provided in promise
|
||||
* and return the filtered networks
|
||||
* @return {Array}
|
||||
*/
|
||||
var filterNetworks = function () {
|
||||
const filterNetworks = function () {
|
||||
const networks = [];
|
||||
for (let network of Array.from(SocialNetworks)) {
|
||||
for (const network of Array.from(SocialNetworks)) {
|
||||
if ($scope.user.profile[network] && ($scope.user.profile[network].length > 0)) {
|
||||
networks.push(network);
|
||||
}
|
||||
|
@ -205,6 +205,15 @@ angular.module('application.router', ['ui.router'])
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('app.logged.dashboard.payment_schedules', {
|
||||
url: '/payment_schedules',
|
||||
views: {
|
||||
'main@': {
|
||||
templateUrl: '/dashboard/payment_schedules.html',
|
||||
controller: 'DashboardController'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('app.logged.dashboard.wallet', {
|
||||
url: '/wallet',
|
||||
abstract: !Fablab.walletModule,
|
||||
|
@ -16,6 +16,7 @@
|
||||
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.trainings" translate>{{ 'app.public.common.my_trainings' }}</a></li>
|
||||
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.events" translate>{{ 'app.public.common.my_events' }}</a></li>
|
||||
<li ui-sref-active="active" ng-show="$root.modules.invoicing"><a class="text-black" href="#" ui-sref="app.logged.dashboard.invoices" translate>{{ 'app.public.common.my_invoices' }}</a></li>
|
||||
<li ui-sref-active="active" ng-show="$root.modules.invoicing"><a class="text-black" href="#" ui-sref="app.logged.dashboard.payment_schedules" translate>{{ 'app.public.common.my_payment_schedules' }}</a></li>
|
||||
<li ng-show="$root.modules.wallet" ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.wallet" translate>{{ 'app.public.common.my_wallet' }}</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
11
app/frontend/templates/dashboard/payment_schedules.html
Normal file
11
app/frontend/templates/dashboard/payment_schedules.html
Normal file
@ -0,0 +1,11 @@
|
||||
<div>
|
||||
|
||||
<section class="heading">
|
||||
<div class="row no-gutter">
|
||||
<ng-include src="'/dashboard/nav.html'"></ng-include>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<payment-schedules-dashboard current-user="currentUser" />
|
||||
</div>
|
@ -10,7 +10,7 @@
|
||||
<span class="avatar avatar-block text-center">
|
||||
<fab-user-avatar ng-model="member.profile.user_avatar" avatar-class="thumb-50"></fab-user-avatar>
|
||||
<!-- <i class="on b-white bottom"></i> -->
|
||||
<a ><span class="user-name m-l-sm m-t-xs">{{member.name}}</span></a>
|
||||
<a><span class="user-name m-l-sm m-t-xs">{{member.name}}</span></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
<li><a ui-sref="app.logged.dashboard.trainings" translate>{{ 'app.public.common.my_trainings' }}</a></li>
|
||||
<li><a ui-sref="app.logged.dashboard.events" translate>{{ 'app.public.common.my_events' }}</a></li>
|
||||
<li><a ui-sref="app.logged.dashboard.invoices" ng-show="$root.modules.invoicing" translate>{{ 'app.public.common.my_invoices' }}</a></li>
|
||||
<li><a ui-sref="app.logged.dashboard.payment_schedules" ng-show="$root.modules.invoicing" translate>{{ 'app.public.common.my_payment_schedules' }}</a></li>
|
||||
<li ng-show="$root.modules.wallet"><a ui-sref="app.logged.dashboard.wallet" translate>{{ 'app.public.common.my_wallet' }}</a></li>
|
||||
<li class="divider" ng-if="isAuthorized(['admin', 'manager'])"></li>
|
||||
<li><a class="text-black pointer" ng-click="help($event)" ng-if="isAuthorized(['admin', 'manager'])"><i class="fa fa-question-circle"></i> <span translate>{{ 'app.public.common.help' }}</span> </a></li>
|
||||
|
8
app/views/api/payment_schedules/index.json.jbuilder
Normal file
8
app/views/api/payment_schedules/index.json.jbuilder
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
max_schedules = @payment_schedules.except(:offset, :limit, :order).count
|
||||
|
||||
json.array! @payment_schedules do |ps|
|
||||
json.max_length max_schedules
|
||||
json.partial! 'api/payment_schedules/payment_schedule', payment_schedule: ps
|
||||
end
|
@ -7,4 +7,4 @@
|
||||
DATE: I18n.l(@attached_object.due_date, format: :long)) %>
|
||||
<%= t('.body.error') %>
|
||||
</p>
|
||||
<p><%= t('.body.action', DASHBOARD: link_to(t('.body.your_dashboard'), "#{root_url}#!/dashboard/invoices")) %></p>
|
||||
<p><%= t('.body.action', DASHBOARD: link_to(t('.body.your_dashboard'), "#{root_url}#!/dashboard/payment_schedules")) %></p>
|
||||
|
@ -14,7 +14,7 @@
|
||||
<p><%= t('.body.schedule_in_your_dashboard_html',
|
||||
DASHBOARD: link_to(
|
||||
t('.body.your_dashboard'),
|
||||
"#{root_url}#!/dashboard/invoices"
|
||||
"#{root_url}#!/dashboard/payment_schedules"
|
||||
)
|
||||
) %>
|
||||
</p>
|
||||
|
@ -19,6 +19,7 @@ en:
|
||||
my_trainings: "My Trainings"
|
||||
my_events: "My Events"
|
||||
my_invoices: "My Invoices"
|
||||
my_payment_schedules: "My payment schedules"
|
||||
my_wallet: "My Wallet"
|
||||
#contextual help
|
||||
help: "Help"
|
||||
|
@ -19,6 +19,7 @@ fr:
|
||||
my_trainings: "Mes formations"
|
||||
my_events: "Mes événements"
|
||||
my_invoices: "Mes factures"
|
||||
my_payment_schedules: "Mes échéanciers de paiement"
|
||||
my_wallet: "Mon porte-monnaie"
|
||||
#contextual help
|
||||
help: "Aide"
|
||||
|
@ -111,7 +111,7 @@ Rails.application.routes.draw do
|
||||
get 'first', action: 'first', on: :collection
|
||||
end
|
||||
|
||||
resources :payment_schedules, only: %i[show] do
|
||||
resources :payment_schedules, only: %i[index show] do
|
||||
post 'list', action: 'list', on: :collection
|
||||
put 'cancel', on: :member
|
||||
get 'download', on: :member
|
||||
|
Loading…
Reference in New Issue
Block a user