From f6889fbfdae67b26ce86c81a9175a8486c3391ca Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 1 Jul 2021 12:34:10 +0200 Subject: [PATCH] linted TSX files --- app/frontend/src/javascript/app.js | 1 - .../javascript/components/angular/switch.ts | 2 +- .../javascript/components/base/fab-alert.tsx | 4 +- .../javascript/components/base/fab-button.tsx | 11 +- .../javascript/components/base/fab-input.tsx | 48 ++-- .../javascript/components/base/fab-modal.tsx | 25 +- .../components/base/fab-popover.tsx | 7 +- .../components/base/html-translate.tsx | 6 +- .../components/base/labelled-input.tsx | 6 +- .../src/javascript/components/base/loader.tsx | 7 +- .../components/document-filters.tsx | 34 +-- .../javascript/components/event-themes.tsx | 25 +- .../components/machines/machine-card.tsx | 33 ++- .../components/machines/machines-filters.tsx | 20 +- .../components/machines/machines-list.tsx | 27 +-- .../machines/pending-training-modal.tsx | 16 +- .../machines/required-training-modal.tsx | 24 +- .../components/machines/reserve-button.tsx | 42 ++-- .../payment-schedule-summary.tsx | 24 +- .../payment-schedules-dashboard.tsx | 31 ++- .../payment-schedules-list.tsx | 33 ++- .../payment-schedules-table.tsx | 229 +++++++++--------- .../payment-schedule/select-schedule.tsx | 8 +- .../payment/abstract-payment-modal.tsx | 65 +++-- .../local-payment/local-payment-form.tsx | 45 ++-- .../local-payment/local-payment-modal.tsx | 61 +++-- .../components/payment/payment-modal.tsx | 39 ++- .../payzen/payzen-card-update-modal.tsx | 37 ++- .../components/payment/payzen/payzen-form.tsx | 28 +-- .../payment/payzen/payzen-keys-form.tsx | 78 +++--- .../payment/payzen/payzen-modal.tsx | 47 ++-- .../payment/payzen/payzen-settings.tsx | 48 ++-- .../stripe/stripe-card-update-modal.tsx | 29 ++- .../payment/stripe/stripe-card-update.tsx | 15 +- .../payment/stripe/stripe-confirm.tsx | 4 +- .../payment/stripe/stripe-elements.tsx | 8 +- .../components/payment/stripe/stripe-form.tsx | 20 +- .../payment/stripe/stripe-keys-form.tsx | 38 ++- .../payment/stripe/stripe-modal.tsx | 47 ++-- .../components/payment/update-card-modal.tsx | 27 +-- .../plan-categories/create-plan-category.tsx | 47 ++-- .../plan-categories/delete-plan-category.tsx | 16 +- .../plan-categories/edit-plan-category.tsx | 40 ++- .../plan-categories/plan-categories-list.tsx | 11 +- .../javascript/components/plans/plan-card.tsx | 54 ++--- .../components/plans/plans-filter.tsx | 30 +-- .../components/plans/plans-list.tsx | 58 +++-- .../prepaid-packs/packs-summary.tsx | 38 +-- .../prepaid-packs/propose-packs-modal.tsx | 64 +++-- .../pricing/configure-packs-button.tsx | 26 +- .../components/pricing/create-pack.tsx | 18 +- .../components/pricing/delete-pack.tsx | 16 +- .../components/pricing/edit-pack.tsx | 20 +- .../components/pricing/editable-price.tsx | 8 +- .../components/pricing/machines-pricing.tsx | 44 ++-- .../components/pricing/pack-form.tsx | 68 +++--- .../components/select-gateway-modal.tsx | 37 ++- .../src/javascript/components/user/avatar.tsx | 7 +- .../src/javascript/components/wallet-info.tsx | 26 +- app/frontend/src/javascript/models/payzen.ts | 2 - 60 files changed, 935 insertions(+), 994 deletions(-) diff --git a/app/frontend/src/javascript/app.js b/app/frontend/src/javascript/app.js index ff0efaebf..429365a3f 100644 --- a/app/frontend/src/javascript/app.js +++ b/app/frontend/src/javascript/app.js @@ -5,7 +5,6 @@ * creating namespaces and moduled for controllers, filters, services, and directives. */ -// eslint-disable-next-line no-use-before-define var Application = Application || {}; Application.Components = angular.module('application.components', []); diff --git a/app/frontend/src/javascript/components/angular/switch.ts b/app/frontend/src/javascript/components/angular/switch.ts index a7ceb2170..50c716d37 100644 --- a/app/frontend/src/javascript/components/angular/switch.ts +++ b/app/frontend/src/javascript/components/angular/switch.ts @@ -5,6 +5,6 @@ import Switch from 'react-switch'; import { react2angular } from 'react2angular'; import { IApplication } from '../../models/application'; -declare let Application: IApplication; +declare const Application: IApplication; Application.Components.component('switch', react2angular(Switch, ['checked', 'onChange', 'id', 'className', 'disabled'])); diff --git a/app/frontend/src/javascript/components/base/fab-alert.tsx b/app/frontend/src/javascript/components/base/fab-alert.tsx index ba40c5f7e..f8a06c83d 100644 --- a/app/frontend/src/javascript/components/base/fab-alert.tsx +++ b/app/frontend/src/javascript/components/base/fab-alert.tsx @@ -10,8 +10,8 @@ interface FabAlertProps { */ export const FabAlert: React.FC = ({ level, className, children }) => { return ( -
+
{children}
- ) + ); }; diff --git a/app/frontend/src/javascript/components/base/fab-button.tsx b/app/frontend/src/javascript/components/base/fab-button.tsx index 32c5ae541..f200d971b 100644 --- a/app/frontend/src/javascript/components/base/fab-button.tsx +++ b/app/frontend/src/javascript/components/base/fab-button.tsx @@ -18,14 +18,14 @@ export const FabButton: React.FC = ({ onClick, icon, className, */ const hasIcon = (): boolean => { return !!icon; - } + }; /** * Check if the current button has children properties (like some text) */ const hasChildren = (): boolean => { return !!children; - } + }; /** * Handle the action of the button @@ -34,15 +34,14 @@ export const FabButton: React.FC = ({ onClick, icon, className, if (typeof onClick === 'function') { onClick(e); } - } + }; return ( - ); -} +}; FabButton.defaultProps = { type: 'button' }; - diff --git a/app/frontend/src/javascript/components/base/fab-input.tsx b/app/frontend/src/javascript/components/base/fab-input.tsx index 515e0c862..3305dfe63 100644 --- a/app/frontend/src/javascript/components/base/fab-input.tsx +++ b/app/frontend/src/javascript/components/base/fab-input.tsx @@ -1,10 +1,12 @@ import React, { BaseSyntheticEvent, ReactNode, useCallback, useEffect, useState } from 'react'; import { debounce as _debounce } from 'lodash'; +type inputType = string|number|readonly string []; + interface FabInputProps { id: string, - onChange?: (value: string, validity?: ValidityState) => void, - defaultValue: any, + onChange?: (value: inputType, validity?: ValidityState) => void, + defaultValue: inputType, icon?: ReactNode, addOn?: ReactNode, addOnClassName?: string, @@ -27,7 +29,7 @@ interface FabInputProps { * This component is a template for an input component that wraps the application style */ export const FabInput: React.FC = ({ id, onChange, defaultValue, icon, className, disabled, type, required, debounce, addOn, addOnClassName, readOnly, maxLength, pattern, placeholder, error, step, min, max }) => { - const [inputValue, setInputValue] = useState(defaultValue); + const [inputValue, setInputValue] = useState(defaultValue); /** * When the component is mounted, initialize the default value for the input. @@ -47,21 +49,21 @@ export const FabInput: React.FC = ({ id, onChange, defaultValue, */ const hasIcon = (): boolean => { return !!icon; - } + }; /** * Check if the current component was provided an add-on element to display, at the end of the input */ const hasAddOn = (): boolean => { return !!addOn; - } + }; /** * Check if the current component was provided an error string to display, on the input */ const hasError = (): boolean => { return !!error; - } + }; /** * Debounced (ie. temporised) version of the 'on change' callback. @@ -81,31 +83,31 @@ export const FabInput: React.FC = ({ id, onChange, defaultValue, onChange(value, validity); } } - } + }; return ( -
+
{hasIcon() && {icon}} - {hasAddOn() && {addOn}} + type={type} + step={step} + min={min} + max={max} + className="fab-input--input" + value={inputValue} + onChange={handleChange} + disabled={disabled} + required={required} + readOnly={readOnly} + maxLength={maxLength} + pattern={pattern} + placeholder={placeholder} /> + {hasAddOn() && {addOn}}
{hasError() && {error} }
); -} +}; FabInput.defaultProps = { type: 'text', debounce: 0 }; diff --git a/app/frontend/src/javascript/components/base/fab-modal.tsx b/app/frontend/src/javascript/components/base/fab-modal.tsx index 6368bffb6..7cc4042db 100644 --- a/app/frontend/src/javascript/components/base/fab-modal.tsx +++ b/app/frontend/src/javascript/components/base/fab-modal.tsx @@ -54,46 +54,46 @@ export const FabModal: React.FC = ({ title, isOpen, toggleModal, */ const hasConfirmButton = (): boolean => { return confirmButton !== undefined; - } + }; /** * Check if the behavior of the confirm button is to send a form, using the provided ID */ const confirmationSendForm = (): boolean => { return onConfirmSendFormId !== undefined; - } + }; /** * Should we display the close button? */ const hasCloseButton = (): boolean => { return closeButton; - } + }; /** * Check if there's a custom footer */ const hasCustomFooter = (): boolean => { return customFooter !== undefined; - } + }; /** * Check if there's a custom header */ const hasCustomHeader = (): boolean => { return customHeader !== undefined; - } + }; return ( + className={`fab-modal fab-modal-${width} ${className}`} + overlayClassName="fab-modal-overlay" + onRequestClose={toggleModal}>
{blackLogo && {blackLogo.custom_asset_file_attributes.attachment}} + alt={blackLogo.custom_asset_file_attributes.attachment} + className="modal-logo" />} {!hasCustomHeader() &&

{ title }

} {hasCustomHeader() && customHeader} @@ -103,7 +103,7 @@ export const FabModal: React.FC = ({ title, isOpen, toggleModal,
- {hasCloseButton() &&{t('app.shared.buttons.close')}} + {hasCloseButton() && {t('app.shared.buttons.close')}} {hasConfirmButton() && !confirmationSendForm() && {confirmButton}} {hasConfirmButton() && confirmationSendForm() && {confirmButton}} {hasCustomFooter() && customFooter} @@ -111,5 +111,4 @@ export const FabModal: React.FC = ({ title, isOpen, toggleModal,
); -} - +}; diff --git a/app/frontend/src/javascript/components/base/fab-popover.tsx b/app/frontend/src/javascript/components/base/fab-popover.tsx index 3438fa746..76571b219 100644 --- a/app/frontend/src/javascript/components/base/fab-popover.tsx +++ b/app/frontend/src/javascript/components/base/fab-popover.tsx @@ -10,16 +10,15 @@ interface FabPopoverProps { * This component is a template for a popovers (bottom) that wraps the application style */ export const FabPopover: React.FC = ({ title, className, headerButton, children }) => { - /** * Check if the header button should be present */ const hasHeaderButton = (): boolean => { return !!headerButton; - } + }; return ( -
+

{title}

{hasHeaderButton() && headerButton} @@ -29,4 +28,4 @@ export const FabPopover: React.FC = ({ title, className, header
); -} +}; diff --git a/app/frontend/src/javascript/components/base/html-translate.tsx b/app/frontend/src/javascript/components/base/html-translate.tsx index 08cfa6988..68abc8b52 100644 --- a/app/frontend/src/javascript/components/base/html-translate.tsx +++ b/app/frontend/src/javascript/components/base/html-translate.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; interface HtmlTranslateProps { trKey: string, - options?: any + options?: Record } /** @@ -13,6 +13,6 @@ export const HtmlTranslate: React.FC = ({ trKey, options }) const { t } = useTranslation(trKey?.split('.')[1]); return ( - + ); -} +}; diff --git a/app/frontend/src/javascript/components/base/labelled-input.tsx b/app/frontend/src/javascript/components/base/labelled-input.tsx index 4da0e6566..1bc0c4d02 100644 --- a/app/frontend/src/javascript/components/base/labelled-input.tsx +++ b/app/frontend/src/javascript/components/base/labelled-input.tsx @@ -1,10 +1,12 @@ import React, { BaseSyntheticEvent, ReactNode } from 'react'; +type inputType = string|number|readonly string []; + interface LabelledInputProps { id: string, type?: 'text' | 'date' | 'password' | 'url' | 'time' | 'tel' | 'search' | 'number' | 'month' | 'email' | 'datetime-local' | 'week', label: string | ReactNode, - value: any, + value: inputType, onChange: (event: BaseSyntheticEvent) => void } @@ -18,4 +20,4 @@ export const LabelledInput: React.FC = ({ id, type, label, v
); -} +}; diff --git a/app/frontend/src/javascript/components/base/loader.tsx b/app/frontend/src/javascript/components/base/loader.tsx index 6da35bf5a..5866e9a19 100644 --- a/app/frontend/src/javascript/components/base/loader.tsx +++ b/app/frontend/src/javascript/components/base/loader.tsx @@ -3,7 +3,7 @@ import React, { Suspense } from 'react'; /** * This component is a wrapper that display a loader while the children components have their rendering suspended */ -export const Loader: React.FC = ({children }) => { +export const Loader: React.FC = ({ children }) => { const loading = (
@@ -11,8 +11,7 @@ export const Loader: React.FC = ({children }) => { ); return ( - {children} + {children} ); -} - +}; diff --git a/app/frontend/src/javascript/components/document-filters.tsx b/app/frontend/src/javascript/components/document-filters.tsx index 87f53d44a..723dc742c 100644 --- a/app/frontend/src/javascript/components/document-filters.tsx +++ b/app/frontend/src/javascript/components/document-filters.tsx @@ -24,21 +24,21 @@ export const DocumentFilters: React.FC = ({ onFilterChange */ useEffect(() => { onFilterChange({ reference: referenceFilter, customer: customerFilter, date: dateFilter }); - }, [referenceFilter, customerFilter, dateFilter]) + }, [referenceFilter, customerFilter, dateFilter]); /** * Callback triggered when the input 'reference' is updated. */ const handleReferenceUpdate = (e) => { setReferenceFilter(e.target.value); - } + }; /** * Callback triggered when the input 'customer' is updated. */ const handleCustomerUpdate = (e) => { setCustomerFilter(e.target.value); - } + }; /** * Callback triggered when the input 'date' is updated. @@ -47,25 +47,25 @@ export const DocumentFilters: React.FC = ({ onFilterChange let date = e.target.value; if (e.target.value === '') date = null; setDateFilter(date); - } + }; return (
+ label={t('app.admin.invoices.document_filters.reference')} + type="text" + onChange={handleReferenceUpdate} + value={referenceFilter} /> + label={t('app.admin.invoices.document_filters.customer')} + type="text" + onChange={handleCustomerUpdate} + value={customerFilter} /> + label={t('app.admin.invoices.document_filters.date')} + type="date" + onChange={handleDateUpdate} + value={dateFilter || ''} />
); -} +}; diff --git a/app/frontend/src/javascript/components/event-themes.tsx b/app/frontend/src/javascript/components/event-themes.tsx index 97158b980..b79ba8929 100644 --- a/app/frontend/src/javascript/components/event-themes.tsx +++ b/app/frontend/src/javascript/components/event-themes.tsx @@ -8,7 +8,7 @@ import { EventTheme } from '../models/event-theme'; import { IApplication } from '../models/application'; import EventThemeAPI from '../api/event-theme'; -declare var Application: IApplication; +declare const Application: IApplication; interface EventThemesProps { event: Event, @@ -51,7 +51,7 @@ const EventThemes: React.FC = ({ event, onChange }) => { } }); return res; - } + }; /** * Callback triggered when the selection has changed. @@ -61,18 +61,18 @@ const EventThemes: React.FC = ({ event, onChange }) => { const res = []; selectedOptions.forEach(opt => { res.push(themes.find(t => t.id === opt.value)); - }) + }); onChange(res); - } + }; /** * Convert all themes to the react-select format */ const buildOptions = (): Array => { return themes.map(t => { - return { value: t.id, label: t.name } + return { value: t.id, label: t.name }; }); - } + }; return (
@@ -80,15 +80,15 @@ const EventThemes: React.FC = ({ event, onChange }) => {

{ t('app.shared.event.event_themes') }

+ id="status" + className="status-select" + onChange={handleStatusSelected} + options={buildBooleanOptions()}/>
- ) -} + ); +}; diff --git a/app/frontend/src/javascript/components/machines/machines-list.tsx b/app/frontend/src/javascript/components/machines/machines-list.tsx index 5177eea62..adf1f0f67 100644 --- a/app/frontend/src/javascript/components/machines/machines-list.tsx +++ b/app/frontend/src/javascript/components/machines/machines-list.tsx @@ -8,7 +8,7 @@ import { MachineCard } from './machine-card'; import { MachinesFilters } from './machines-filters'; import { User } from '../../models/user'; -declare var Application: IApplication; +declare const Application: IApplication; interface MachinesListProps { user?: User, @@ -39,7 +39,7 @@ const MachinesList: React.FC = ({ onError, onSuccess, onShowM // filter the machines shown when the full list was retrieved useEffect(() => { handleFilterByStatus(true); - }, [allMachines]) + }, [allMachines]); /** * Callback triggered when the user changes the status filter. @@ -53,7 +53,7 @@ const MachinesList: React.FC = ({ onError, onSuccess, onShowM // enabled machines may have the m.disabled property null (for never disabled machines) // or false (for re-enabled machines) setMachines(allMachines.filter(m => !!m.disabled === !status)); - } + }; return (
@@ -61,20 +61,19 @@ const MachinesList: React.FC = ({ onError, onSuccess, onShowM
{machines && machines.map(machine => { return + user={user} + machine={machine} + onShowMachine={onShowMachine} + onReserveMachine={onReserveMachine} + onError={onError} + onSuccess={onSuccess} + onLoginRequested={onLoginRequested} + onEnrollRequested={onEnrollRequested} />; })}
); -} - +}; const MachinesListWrapper: React.FC = ({ user, onError, onSuccess, onShowMachine, onReserveMachine, onLoginRequested, onEnrollRequested }) => { return ( @@ -82,6 +81,6 @@ const MachinesListWrapper: React.FC = ({ user, onError, onSuc ); -} +}; Application.Components.component('machinesList', react2angular(MachinesListWrapper, ['user', 'onError', 'onSuccess', 'onShowMachine', 'onReserveMachine', 'onLoginRequested', 'onEnrollRequested'])); diff --git a/app/frontend/src/javascript/components/machines/pending-training-modal.tsx b/app/frontend/src/javascript/components/machines/pending-training-modal.tsx index 8f83b195d..3c732b321 100644 --- a/app/frontend/src/javascript/components/machines/pending-training-modal.tsx +++ b/app/frontend/src/javascript/components/machines/pending-training-modal.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { HtmlTranslate } from '../base/html-translate'; import { IFablab } from '../../models/fablab'; -declare var Fablab: IFablab; +declare let Fablab: IFablab; interface PendingTrainingModalProps { isOpen: boolean, @@ -26,16 +26,16 @@ export const PendingTrainingModal: React.FC = ({ isOp const formatDateTime = (date: Date): string => { const day = Intl.DateTimeFormat().format(moment(date).toDate()); const time = Intl.DateTimeFormat(Fablab.intl_locale, { hour: 'numeric', minute: 'numeric' }).format(moment(date).toDate()); - return t('app.logged.pending_training_modal.DATE_TIME', { DATE: day, TIME:time }); - } + return t('app.logged.pending_training_modal.DATE_TIME', { DATE: day, TIME: time }); + }; return ( + isOpen={isOpen} + toggleModal={toggleModal} + closeButton={true}>

{t('app.logged.pending_training_modal.wait_for_validated')}

- ) -} + ); +}; diff --git a/app/frontend/src/javascript/components/machines/required-training-modal.tsx b/app/frontend/src/javascript/components/machines/required-training-modal.tsx index 42ff0f4aa..7054754b1 100644 --- a/app/frontend/src/javascript/components/machines/required-training-modal.tsx +++ b/app/frontend/src/javascript/components/machines/required-training-modal.tsx @@ -27,14 +27,14 @@ export const RequiredTrainingModal: React.FC = ({ is if (!machine) return ''; return machine.trainings.map(t => t.name).join(t('app.logged.required_training_modal.training_or_training_html')); - } + }; /** * Callback triggered when the user has clicked on the "enroll" button */ const handleEnroll = (): void => { onEnrollRequested(machine.trainings[0].id); - } + }; /** * Custom header of the dialog: we display the username and avatar @@ -46,7 +46,7 @@ export const RequiredTrainingModal: React.FC = ({ is {user?.name}
); - } + }; /** * Custom footer of the dialog: we display a user-friendly message to close the dialog @@ -58,24 +58,24 @@ export const RequiredTrainingModal: React.FC = ({ is {t('app.logged.required_training_modal.close')}
); - } + }; return ( + toggleModal={toggleModal} + className="required-training-modal" + closeButton={false} + customHeader={header()} + customFooter={footer()}>

+ options={{ MACHINE: machine?.name, TRAINING: formatTrainings() }} />

{t('app.logged.required_training_modal.enroll_now')}
- ) -} + ); +}; diff --git a/app/frontend/src/javascript/components/machines/reserve-button.tsx b/app/frontend/src/javascript/components/machines/reserve-button.tsx index 4f9cad2a8..606a37b93 100644 --- a/app/frontend/src/javascript/components/machines/reserve-button.tsx +++ b/app/frontend/src/javascript/components/machines/reserve-button.tsx @@ -10,7 +10,7 @@ import { Machine } from '../../models/machine'; import { User } from '../../models/user'; import { IApplication } from '../../models/application'; -declare var Application: IApplication; +declare const Application: IApplication; interface ReserveButtonProps { currentUser?: User, @@ -86,7 +86,7 @@ const ReserveButtonComponent: React.FC = ({ currentUser, mac */ const toggleProposePacksModal = (): void => { setProposePacks(!proposePacks); - } + }; /** * Callback triggered when the user has successfully bought a pre-paid pack. @@ -95,7 +95,7 @@ const ReserveButtonComponent: React.FC = ({ currentUser, mac const handlePackBought = (message: string, machine: Machine): void => { onSuccess(message); onReserveMachine(machine); - } + }; /** * Check that the current user has passed the required training before allowing him to book @@ -143,35 +143,35 @@ const ReserveButtonComponent: React.FC = ({ currentUser, mac // otherwise, we show a dialog modal to propose the customer to buy an available pack setProposePacks(true); - } + }; return ( - + toggleModal={togglePendingTrainingModal} + nextReservation={machine?.current_user_next_training_reservation?.slots_attributes[0]?.start_at} /> + toggleModal={toggleRequiredTrainingModal} + user={user} + machine={machine} + onEnrollRequested={onEnrollRequested} /> {machine && currentUser && } + toggleModal={toggleProposePacksModal} + item={machine} + itemType="Machine" + onError={onError} + customer={currentUser} + onDecline={onReserveMachine} + operator={currentUser} + onSuccess={handlePackBought} />} ); -} +}; export const ReserveButton: React.FC = ({ currentUser, machineId, onLoginRequested, onLoadingStart, onLoadingEnd, onError, onSuccess, onReserveMachine, onEnrollRequested, className, children }) => { return ( @@ -181,6 +181,6 @@ export const ReserveButton: React.FC = ({ currentUser, machi ); -} +}; Application.Components.component('reserveButton', react2angular(ReserveButton, ['currentUser', 'machineId', 'onLoadingStart', 'onLoadingEnd', 'onError', 'onSuccess', 'onReserveMachine', 'onLoginRequested', 'onEnrollRequested', 'className'])); diff --git a/app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx b/app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx index 3e217cc59..5ac79dfd9 100644 --- a/app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx +++ b/app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx @@ -8,7 +8,7 @@ import { PaymentSchedule } from '../../models/payment-schedule'; import { IApplication } from '../../models/application'; import FormatLib from '../../lib/format'; -declare var Application: IApplication; +declare const Application: IApplication; interface PaymentScheduleSummaryProps { schedule: PaymentSchedule @@ -29,13 +29,13 @@ const PaymentScheduleSummary: React.FC = ({ schedul const hasEqualDeadlines = (): boolean => { const prices = schedule.items.map(i => i.amount); return prices.every(p => p === prices[0]); - } + }; /** * Open or closes the modal dialog showing the full payment schedule */ const toggleFullScheduleModal = (): void => { setModal(!modal); - } + }; return (
@@ -64,25 +64,25 @@ const PaymentScheduleSummary: React.FC = ({ schedul
    - {schedule.items.map(item => ( -
  • - {FormatLib.date(item.due_date)} - - {FormatLib.price(item.amount)} -
  • - ))} + {schedule.items.map(item => ( +
  • + {FormatLib.date(item.due_date)} + + {FormatLib.price(item.amount)} +
  • + ))}
); -} +}; const PaymentScheduleSummaryWrapper: React.FC = ({ schedule }) => { return ( ); -} +}; Application.Components.component('paymentScheduleSummary', react2angular(PaymentScheduleSummaryWrapper, ['schedule'])); diff --git a/app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx b/app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx index 02abe098a..19a3d6f08 100644 --- a/app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx +++ b/app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx @@ -9,7 +9,7 @@ import { PaymentSchedule } from '../../models/payment-schedule'; import { IApplication } from '../../models/application'; import PaymentScheduleAPI from '../../api/payment-schedule'; -declare var Application: IApplication; +declare const Application: IApplication; interface PaymentSchedulesDashboardProps { currentUser: User, @@ -45,60 +45,59 @@ const PaymentSchedulesDashboard: React.FC = ({ c const handleLoadMore = (): void => { setPageNumber(pageNumber + 1); - PaymentScheduleAPI.index({ query: { page: pageNumber + 1, size: PAGE_SIZE }}).then((res) => { + PaymentScheduleAPI.index({ query: { page: pageNumber + 1, size: PAGE_SIZE } }).then((res) => { const list = paymentSchedules.concat(res); setPaymentSchedules(list); }).catch((error) => onError(error.message)); - } + }; /** * Reload from te API all the currently displayed payment schedules */ const handleRefreshList = (): void => { - PaymentScheduleAPI.index({ query: { page: 1, size: PAGE_SIZE * pageNumber }}).then((res) => { + PaymentScheduleAPI.index({ query: { page: 1, size: PAGE_SIZE * pageNumber } }).then((res) => { setPaymentSchedules(res); }).catch((err) => { onError(err.message); }); - } + }; /** * after a successful card update, provide a success message to the end-user */ const handleCardUpdateSuccess = (): void => { onCardUpdateSuccess(t('app.logged.dashboard.payment_schedules.card_updated_success')); - } + }; /** * 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 (
{!hasSchedules() &&
{t('app.logged.dashboard.payment_schedules.no_payment_schedules')}
} {hasSchedules() &&
+ showCustomer={false} + refreshList={handleRefreshList} + operator={currentUser} + onError={onError} + onCardUpdateSuccess={handleCardUpdateSuccess} /> {hasMoreSchedules() && {t('app.logged.dashboard.payment_schedules.load_more')}}
}
); -} - +}; const PaymentSchedulesDashboardWrapper: React.FC = ({ currentUser, onError, onCardUpdateSuccess }) => { return ( @@ -106,6 +105,6 @@ const PaymentSchedulesDashboardWrapper: React.FC ); -} +}; Application.Components.component('paymentSchedulesDashboard', react2angular(PaymentSchedulesDashboardWrapper, ['currentUser', 'onError', 'onCardUpdateSuccess'])); diff --git a/app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx b/app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx index 8533dbb55..7288fba22 100644 --- a/app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx +++ b/app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx @@ -10,7 +10,7 @@ import { PaymentSchedule } from '../../models/payment-schedule'; import { IApplication } from '../../models/application'; import PaymentScheduleAPI from '../../api/payment-schedule'; -declare var Application: IApplication; +declare const Application: IApplication; interface PaymentSchedulesListProps { currentUser: User, @@ -53,7 +53,7 @@ const PaymentSchedulesList: React.FC = ({ currentUser setCustomerFilter(customer); setDateFilter(date); - PaymentScheduleAPI.list({ query: { reference, customer, date, page: 1, size: PAGE_SIZE }}).then((res) => { + PaymentScheduleAPI.list({ query: { reference, customer, date, page: 1, size: PAGE_SIZE } }).then((res) => { setPaymentSchedules(res); }).catch((error) => onError(error.message)); }; @@ -64,43 +64,43 @@ const PaymentSchedulesList: React.FC = ({ currentUser const handleLoadMore = (): void => { setPageNumber(pageNumber + 1); - PaymentScheduleAPI.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: pageNumber + 1, size: PAGE_SIZE }}).then((res) => { + PaymentScheduleAPI.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: pageNumber + 1, size: PAGE_SIZE } }).then((res) => { const list = paymentSchedules.concat(res); setPaymentSchedules(list); }).catch((error) => onError(error.message)); - } + }; /** * Reload from te API all the currently displayed payment schedules */ const handleRefreshList = (): void => { - PaymentScheduleAPI.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: 1, size: PAGE_SIZE * pageNumber }}).then((res) => { + PaymentScheduleAPI.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: 1, size: PAGE_SIZE * pageNumber } }).then((res) => { setPaymentSchedules(res); }).catch((err) => { onError(err.message); }); - } + }; /** * 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; - } + }; /** * after a successful card update, provide a success message to the operator */ const handleCardUpdateSuccess = (): void => { onCardUpdateSuccess(t('app.admin.invoices.payment_schedules.card_updated_success')); - } + }; return (
@@ -114,17 +114,16 @@ const PaymentSchedulesList: React.FC = ({ currentUser {!hasSchedules() &&
{t('app.admin.invoices.payment_schedules.no_payment_schedules')}
} {hasSchedules() &&
+ showCustomer={true} + refreshList={handleRefreshList} + operator={currentUser} + onError={onError} + onCardUpdateSuccess={handleCardUpdateSuccess} /> {hasMoreSchedules() && {t('app.admin.invoices.payment_schedules.load_more')}}
}
); -} - +}; const PaymentSchedulesListWrapper: React.FC = ({ currentUser, onError, onCardUpdateSuccess }) => { return ( @@ -132,6 +131,6 @@ const PaymentSchedulesListWrapper: React.FC = ({ curr ); -} +}; Application.Components.component('paymentSchedulesList', react2angular(PaymentSchedulesListWrapper, ['currentUser', 'onError', 'onCardUpdateSuccess'])); diff --git a/app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx b/app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx index ce1afadf3..7846939f8 100644 --- a/app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx +++ b/app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx @@ -52,18 +52,18 @@ const PaymentSchedulesTableComponent: React.FC = ({ */ const isExpanded = (paymentScheduleId: number): boolean => { return showExpanded.get(paymentScheduleId); - } + }; /** * Return the value for the CSS property 'display', for the payment schedule deadlines */ const statusDisplay = (paymentScheduleId: number): string => { if (isExpanded(paymentScheduleId)) { - return 'table-row' + return 'table-row'; } else { return 'none'; } - } + }; /** * Return the action icon for showing/hiding the deadlines @@ -72,9 +72,9 @@ const PaymentSchedulesTableComponent: React.FC = ({ if (isExpanded(paymentScheduleId)) { return ; } else { - return + return ; } - } + }; /** * Show or hide the deadlines for the provided payment schedule, inverting their current status @@ -86,8 +86,8 @@ const PaymentSchedulesTableComponent: React.FC = ({ } else { setShowExpanded((prev) => new Map(prev).set(paymentScheduleId, true)); } - } - } + }; + }; /** * For use with downloadButton() @@ -103,12 +103,12 @@ const PaymentSchedulesTableComponent: React.FC = ({ const downloadButton = (target: TargetType, id: number): JSX.Element => { const link = `api/${target}/${id}/download`; return ( - + {t('app.shared.schedules_table.download')} ); - } + }; /** * Return the human-readable string for the status of the provided deadline. @@ -116,18 +116,18 @@ const PaymentSchedulesTableComponent: React.FC = ({ const formatState = (item: PaymentScheduleItem): JSX.Element => { let res = t(`app.shared.schedules_table.state_${item.state}`); if (item.state === PaymentScheduleItemState.Paid) { - const key = `app.shared.schedules_table.method_${item.payment_method}` + const key = `app.shared.schedules_table.method_${item.payment_method}`; res += ` (${t(key)})`; } return {res}; - } + }; /** * Check if the current operator has administrative rights or is a normal member */ const isPrivileged = (): boolean => { - return (operator.role === UserRole.Admin || operator.role == UserRole.Manager); - } + return (operator.role === UserRole.Admin || operator.role === UserRole.Manager); + }; /** * Return the action button(s) for the given deadline @@ -140,24 +140,24 @@ const PaymentSchedulesTableComponent: React.FC = ({ if (isPrivileged()) { return ( }> + icon={}> {t('app.shared.schedules_table.confirm_payment')} ); } else { - return {t('app.shared.schedules_table.please_ask_reception')} + return {t('app.shared.schedules_table.please_ask_reception')}; } case PaymentScheduleItemState.RequireAction: return ( }> + icon={}> {t('app.shared.schedules_table.solve')} ); case PaymentScheduleItemState.RequirePaymentMethod: return ( }> + icon={}> {t('app.shared.schedules_table.update_card')} ); @@ -167,28 +167,28 @@ const PaymentSchedulesTableComponent: React.FC = ({ if (isPrivileged()) { return ( }> + icon={}> {t('app.shared.schedules_table.cancel_subscription')} - ) + ); } else { - return {t('app.shared.schedules_table.please_ask_reception')} + return {t('app.shared.schedules_table.please_ask_reception')}; } case PaymentScheduleItemState.New: if (!cardUpdateButton.get(schedule.id)) { cardUpdateButton.set(schedule.id, true); return ( }> + icon={}> {t('app.shared.schedules_table.update_card')} - ) + ); } - return + return ; default: - return + return ; } - } + }; /** * Callback triggered when the user's clicks on the "cash check" button: show a confirmation modal @@ -197,8 +197,8 @@ const PaymentSchedulesTableComponent: React.FC = ({ return (): void => { setTempDeadline(item); toggleConfirmCashingModal(); - } - } + }; + }; /** * After the user has confirmed that he wants to cash the check, update the API, refresh the list and close the modal. @@ -210,28 +210,28 @@ const PaymentSchedulesTableComponent: React.FC = ({ toggleConfirmCashingModal(); } }); - } + }; /** * Refresh all payment schedules in the table */ const refreshSchedulesTable = (): void => { refreshList(); - } + }; /** * Show/hide the modal dialog that enable to confirm the cashing of the check for a given deadline. */ const toggleConfirmCashingModal = (): void => { setShowConfirmCashing(!showConfirmCashing); - } + }; /** * Show/hide the modal dialog that trigger the card "action". */ const toggleResolveActionModal = (): void => { setShowResolveAction(!showResolveAction); - } + }; /** * Callback triggered when the user's clicks on the "resolve" button: show a modal that will trigger the action @@ -240,8 +240,8 @@ const PaymentSchedulesTableComponent: React.FC = ({ return (): void => { setTempDeadline(item); toggleResolveActionModal(); - } - } + }; + }; /** * After the action was done (successfully or not), ask the API to refresh the item status, then refresh the list and close the modal @@ -252,14 +252,14 @@ const PaymentSchedulesTableComponent: React.FC = ({ refreshSchedulesTable(); toggleResolveActionModal(); }); - } + }; /** * Enable/disable the confirm button of the "action" modal */ const toggleConfirmActionButton = (): void => { setConfirmActionDisabled(!isConfirmActionDisabled); - } + }; /** * Callback triggered when the user's clicks on the "update card" button: show a modal to input a new card @@ -269,15 +269,15 @@ const PaymentSchedulesTableComponent: React.FC = ({ setTempDeadline(item); setTempSchedule(paymentSchedule); toggleUpdateCardModal(); - } - } + }; + }; /** * Show/hide the modal dialog to update the bank card details */ const toggleUpdateCardModal = (): void => { setShowUpdateCard(!showUpdateCard); - } + }; /** * When the card was successfully updated, pay the invoice (using the new payment method) and close the modal @@ -296,14 +296,14 @@ const PaymentSchedulesTableComponent: React.FC = ({ onCardUpdateSuccess(); toggleUpdateCardModal(); } - } + }; /** * When the card was not updated, raise the error */ const handleCardUpdateError = (error): void => { onError(error); - } + }; /** * Callback triggered when the user clicks on the "cancel subscription" button @@ -312,15 +312,15 @@ const PaymentSchedulesTableComponent: React.FC = ({ return (): void => { setTempSchedule(schedule); toggleCancelSubscriptionModal(); - } - } + }; + }; /** * Show/hide the modal dialog to cancel the current subscription */ const toggleCancelSubscriptionModal = (): void => { setShowCancelSubscription(!showCancelSubscription); - } + }; /** * When the user has confirmed the cancellation, we transfer the request to the API @@ -330,72 +330,72 @@ const PaymentSchedulesTableComponent: React.FC = ({ refreshSchedulesTable(); toggleCancelSubscriptionModal(); }); - } + }; return (
- - - - - {showCustomer && } - + + + + + {showCustomer && } + - {paymentSchedules.map(p => - - )} + {paymentSchedules.map(p => + + )}
- {t('app.shared.schedules_table.schedule_num')}{t('app.shared.schedules_table.date')}{t('app.shared.schedules_table.price')}{t('app.shared.schedules_table.customer')} -
+ {t('app.shared.schedules_table.schedule_num')}{t('app.shared.schedules_table.date')}{t('app.shared.schedules_table.price')}{t('app.shared.schedules_table.customer')} +
- - - - - - - - {showCustomer && } - - - - - - -
{expandCollapseIcon(p.id)}{p.reference}{FormatLib.date(p.created_at)}{FormatLib.price(p.total)}{p.user.name}{downloadButton(TargetType.PaymentSchedule, p.id)}
- -
- - - - - - - - - - {_.orderBy(p.items, 'due_date').map(item => - - - - - )} - -
{t('app.shared.schedules_table.deadline')}{t('app.shared.schedules_table.amount')}{t('app.shared.schedules_table.state')} -
{FormatLib.date(item.due_date)}{FormatLib.price(item.amount)}{formatState(item)}{itemButtons(item, p)}
-
-
-
+ + + + + + + + {showCustomer && } + + + + + + +
{expandCollapseIcon(p.id)}{p.reference}{FormatLib.date(p.created_at)}{FormatLib.price(p.total)}{p.user.name}{downloadButton(TargetType.PaymentSchedule, p.id)}
+ +
+ + + + + + + + + + {_.orderBy(p.items, 'due_date').map(item => + + + + + )} + +
{t('app.shared.schedules_table.deadline')}{t('app.shared.schedules_table.amount')}{t('app.shared.schedules_table.state')} +
{FormatLib.date(item.due_date)}{FormatLib.price(item.amount)}{formatState(item)}{itemButtons(item, p)}
+
+
+
+ isOpen={showConfirmCashing} + toggleModal={toggleConfirmCashingModal} + onConfirm={onCheckCashingConfirmed} + closeButton={true} + confirmButton={t('app.shared.schedules_table.confirm_button')}> {tempDeadline && {t('app.shared.schedules_table.confirm_check_cashing_body', { AMOUNT: FormatLib.price(tempDeadline.amount), @@ -404,28 +404,28 @@ const PaymentSchedulesTableComponent: React.FC = ({ } + isOpen={showCancelSubscription} + toggleModal={toggleCancelSubscriptionModal} + onConfirm={onCancelSubscriptionConfirmed} + closeButton={true} + confirmButton={t('app.shared.schedules_table.confirm_button')}> {t('app.shared.schedules_table.confirm_cancel_subscription')} + isOpen={showResolveAction} + toggleModal={toggleResolveActionModal} + onConfirm={afterAction} + confirmButton={t('app.shared.schedules_table.ok_button')} + preventConfirm={isConfirmActionDisabled}> {tempDeadline && } {tempSchedule && + toggleModal={toggleUpdateCardModal} + operator={operator} + afterSuccess={handleCardUpdateSuccess} + onError={handleCardUpdateError} + schedule={tempSchedule}> }
@@ -434,11 +434,10 @@ const PaymentSchedulesTableComponent: React.FC = ({ }; PaymentSchedulesTableComponent.defaultProps = { showCustomer: false }; - export const PaymentSchedulesTable: React.FC = ({ paymentSchedules, showCustomer, refreshList, operator, onError, onCardUpdateSuccess }) => { return ( ); -} +}; diff --git a/app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx b/app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx index 6be8451aa..bff5e0b52 100644 --- a/app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx +++ b/app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from 'react'; import { useTranslation } from 'react-i18next'; import { react2angular } from 'react2angular'; import Switch from 'react-switch'; @@ -6,7 +6,7 @@ import '../../lib/i18n'; import { Loader } from '../base/loader'; import { IApplication } from '../../models/application'; -declare var Application: IApplication; +declare const Application: IApplication; interface SelectScheduleProps { show: boolean, @@ -30,7 +30,7 @@ const SelectSchedule: React.FC = ({ show, selected, onChang
} ); -} +}; const SelectScheduleWrapper: React.FC = ({ show, selected, onChange, className }) => { return ( @@ -38,6 +38,6 @@ const SelectScheduleWrapper: React.FC = ({ show, selected, ); -} +}; Application.Components.component('selectSchedule', react2angular(SelectScheduleWrapper, ['show', 'selected', 'onChange', 'className'])); diff --git a/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx b/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx index b5e06d90f..35b7199a0 100644 --- a/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx @@ -18,7 +18,6 @@ import { ComputePriceResult } from '../../models/price'; import { Wallet } from '../../models/wallet'; import FormatLib from '../../lib/format'; - export interface GatewayFormProps { onSubmit: () => void, onSuccess: (result: Invoice|PaymentSchedule) => void, @@ -78,7 +77,6 @@ export const AbstractPaymentModal: React.FC = ({ isOp const { t } = useTranslation('shared'); - /** * When the component loads first, get the name of the currently active payment modal */ @@ -87,7 +85,7 @@ export const AbstractPaymentModal: React.FC = ({ isOp SettingAPI.get(SettingName.PaymentGateway).then((setting) => { // we capitalize the first letter of the name setGateway(setting.value.replace(/^\w/, (c) => c.toUpperCase())); - }) + }); }, []); /** @@ -104,8 +102,8 @@ export const AbstractPaymentModal: React.FC = ({ isOp setPrice(res); setRemainingPrice(new WalletLib(wallet).computeRemainingPrice(res.price)); setReady(true); - }) - }) + }); + }); }, [cart]); /** @@ -113,35 +111,35 @@ export const AbstractPaymentModal: React.FC = ({ isOp */ const hasErrors = (): boolean => { return errors !== null; - } + }; /** * Check if the user accepts the Terms of Sales document */ const hasCgv = (): boolean => { return cgv != null && !preventCgv; - } + }; /** * Triggered when the user accepts or declines the Terms of Sales */ const toggleTos = (): void => { setTos(!tos); - } + }; /** * Check if we must display the info box about the payment schedule */ const hasPaymentScheduleInfo = (): boolean => { return schedule !== undefined && !preventScheduleInfo; - } + }; /** * Set the component as 'currently submitting' */ const handleSubmit = (): void => { setSubmitState(true); - } + }; /** * After sending the form with success, process the resulting payment method @@ -149,7 +147,7 @@ export const AbstractPaymentModal: React.FC = ({ isOp const handleFormSuccess = async (result: Invoice|PaymentSchedule): Promise => { setSubmitState(false); afterSuccess(result); - } + }; /** * When the payment form raises an error, it is handled by this callback which display it in the modal. @@ -157,7 +155,7 @@ export const AbstractPaymentModal: React.FC = ({ isOp const handleFormError = (message: string): void => { setSubmitState(false); setErrors(message); - } + }; /** * Check the form can be submitted. @@ -167,7 +165,7 @@ export const AbstractPaymentModal: React.FC = ({ isOp let terms = true; if (hasCgv()) { terms = tos; } return !submitState && terms; - } + }; /** * Build the modal title. If the provided title is a shared translation key, interpolate it through the @@ -178,28 +176,27 @@ export const AbstractPaymentModal: React.FC = ({ isOp return t(title); } return title; - } - + }; return ( + isOpen={isOpen} + toggleModal={toggleModal} + width={modalSize} + closeButton={false} + customFooter={logoFooter} + className={`payment-modal ${className || ''}`}> {ready &&
+ onSuccess={handleFormSuccess} + onError={handleFormError} + operator={currentUser} + className={`gateway-form ${formClassName || ''}`} + formId={formId} + cart={cart} + customer={customer} + paymentSchedule={schedule}> {hasErrors() &&
{errors}
} @@ -209,16 +206,16 @@ export const AbstractPaymentModal: React.FC = ({ isOp {hasCgv() &&
}
{!submitState && } {submitState &&
@@ -229,7 +226,7 @@ export const AbstractPaymentModal: React.FC = ({ isOp
} ); -} +}; AbstractPaymentModal.defaultProps = { title: 'app.shared.payment.online_payment', diff --git a/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx b/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx index a031b6e8f..a111f16cf 100644 --- a/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx +++ b/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx @@ -9,7 +9,6 @@ import { SettingName } from '../../../models/setting'; import { PaymentModal } from '../payment-modal'; import { PaymentSchedule } from '../../../models/payment-schedule'; - const ALL_SCHEDULE_METHODS = ['card', 'check'] as const; type scheduleMethod = typeof ALL_SCHEDULE_METHODS[number]; @@ -25,7 +24,6 @@ type selectOption = { value: scheduleMethod, label: string }; * The form validation button must be created elsewhere, using the attribute form={formId}. */ export const LocalPaymentForm: React.FC = ({ onSubmit, onSuccess, onError, children, className, paymentSchedule, cart, customer, operator, formId }) => { - const { t } = useTranslation('admin'); const [method, setMethod] = useState('check'); @@ -36,14 +34,14 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce */ const toggleOnlinePaymentModal = (): void => { setOnlinePaymentModal(!onlinePaymentModal); - } + }; /** * Convert all payement methods for schedules to the react-select format */ const buildMethodOptions = (): Array => { return ALL_SCHEDULE_METHODS.map(i => methodToOption(i)); - } + }; /** * Convert the given payment-method to the react-select format @@ -52,15 +50,14 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce if (!value) return { value, label: '' }; return { value, label: t(`app.admin.local_payment.method_${value}`) }; - } - + }; /** * Callback triggered when the user selects a payment method for the current payment schedule. */ const handleUpdateMethod = (option: selectOption) => { setMethod(option.value); - } + }; /** * Handle the submission of the form. It will process the local payment. @@ -74,7 +71,7 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce try { const online = await SettingAPI.get(SettingName.OnlinePaymentModule); if (online.value !== 'true') { - return onError(t('app.admin.local_payment.online_payment_disabled')) + return onError(t('app.admin.local_payment.online_payment_disabled')); } return toggleOnlinePaymentModal(); } catch (e) { @@ -88,7 +85,7 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce } catch (e) { onError(e); } - } + }; /** * Callback triggered after a successful payment by online card for a schedule. @@ -96,20 +93,20 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce const afterCreatePaymentSchedule = (document: PaymentSchedule) => { toggleOnlinePaymentModal(); onSuccess(document); - } + }; return ( -
+ {!paymentSchedule &&

{t('app.admin.local_payment.about_to_cash')}

} {paymentSchedule &&
+ id="group" + className="group-select" + onChange={handleGroupSelected} + options={buildGroupOptions()}/>
} {durations &&
+ className="select-interval" + defaultValue={intervalToOption(packData?.validity_interval)} + onChange={handleUpdateValidityInterval} + options={buildOptions()} />
@@ -142,4 +142,4 @@ export const PackForm: React.FC = ({ formId, onSubmit, pack }) =>
); -} +}; diff --git a/app/frontend/src/javascript/components/select-gateway-modal.tsx b/app/frontend/src/javascript/components/select-gateway-modal.tsx index 231377750..a8b68b6e3 100644 --- a/app/frontend/src/javascript/components/select-gateway-modal.tsx +++ b/app/frontend/src/javascript/components/select-gateway-modal.tsx @@ -16,8 +16,7 @@ import { SettingBulkResult, SettingName } from '../models/setting'; import { IApplication } from '../models/application'; import SettingAPI from '../api/setting'; - -declare var Application: IApplication; +declare const Application: IApplication; interface SelectGatewayModalModalProps { isOpen: boolean, @@ -37,8 +36,8 @@ const SelectGatewayModal: React.FC = ({ isOpen, to // request the configured gateway to the API useEffect(() => { SettingAPI.get(SettingName.PaymentGateway).then(gateway => { - setSelectedGateway(gateway.value ? gateway.value : ''); - }) + setSelectedGateway(gateway.value ? gateway.value : ''); + }); }, []); /** @@ -48,7 +47,7 @@ const SelectGatewayModal: React.FC = ({ isOpen, to setPreventConfirmGateway(true); updateSettings(); setPreventConfirmGateway(false); - } + }; /** * Save the gateway provided by the target input into the component state @@ -56,14 +55,14 @@ const SelectGatewayModal: React.FC = ({ isOpen, to const setGateway = (event: BaseSyntheticEvent) => { const gateway = event.target.value; setSelectedGateway(gateway); - } + }; /** * Check if any payment gateway was selected */ const hasSelectedGateway = (): boolean => { return selectedGateway !== ''; - } + }; /** * Callback triggered when the embedded form has validated all the stripe keys @@ -76,7 +75,7 @@ const SelectGatewayModal: React.FC = ({ isOpen, to return newMap; }); setPreventConfirmGateway(false); - } + }; /** * Callback triggered when the embedded form has validated all the PayZen keys @@ -84,14 +83,14 @@ const SelectGatewayModal: React.FC = ({ isOpen, to const handleValidPayZenKeys = (payZenKeys: Map): void => { setGatewayConfig(payZenKeys); setPreventConfirmGateway(false); - } + }; /** * Callback triggered when the embedded form has not validated all keys */ const handleInvalidKeys = (): void => { setPreventConfirmGateway(true); - } + }; /** * Send the new gateway settings to the API to save them @@ -111,17 +110,17 @@ const SelectGatewayModal: React.FC = ({ isOpen, to }, reason => { onError(reason); }); - } + }; return ( + isOpen={isOpen} + toggleModal={toggleModal} + width={ModalSize.medium} + className="gateway-modal" + confirmButton={t('app.admin.invoices.payment.gateway_modal.confirm_button')} + onConfirm={onGatewayConfirmed} + preventConfirm={preventConfirmGateway}> {!hasSelectedGateway() &&

{t('app.admin.invoices.payment.gateway_modal.gateway_info')}

} @@ -143,6 +142,6 @@ const SelectGatewayModalWrapper: React.FC = ({ isO ); -} +}; Application.Components.component('selectGatewayModal', react2angular(SelectGatewayModalWrapper, ['isOpen', 'toggleModal', 'currentUser', 'onSuccess', 'onError'])); diff --git a/app/frontend/src/javascript/components/user/avatar.tsx b/app/frontend/src/javascript/components/user/avatar.tsx index b61155049..7fe47f2b2 100644 --- a/app/frontend/src/javascript/components/user/avatar.tsx +++ b/app/frontend/src/javascript/components/user/avatar.tsx @@ -12,18 +12,17 @@ interface AvatarProps { * This component renders the user-profile's picture or a placeholder */ export const Avatar: React.FC = ({ user, className }) => { - /** * Check if the provided user has a configured avatar */ const hasAvatar = (): boolean => { return !!user?.profile?.user_avatar?.attachment_url; - } + }; return ( -
+
{!hasAvatar() && avatar placeholder} {hasAvatar() && user's avatar}
); -} +}; diff --git a/app/frontend/src/javascript/components/wallet-info.tsx b/app/frontend/src/javascript/components/wallet-info.tsx index 4d927d050..052808b72 100644 --- a/app/frontend/src/javascript/components/wallet-info.tsx +++ b/app/frontend/src/javascript/components/wallet-info.tsx @@ -10,7 +10,7 @@ import WalletLib from '../lib/wallet'; import { ShoppingCart } from '../models/payment'; import FormatLib from '../lib/format'; -declare var Application: IApplication; +declare const Application: IApplication; interface WalletInfoProps { cart: ShoppingCart, @@ -39,27 +39,27 @@ export const WalletInfo: React.FC = ({ cart, currentUser, walle * If the currently connected user (i.e. the operator), is an admin or a manager, he may book the reservation for someone else. */ const isOperatorAndClient = (): boolean => { - return currentUser.id == cart.customer_id; - } + return currentUser.id === cart.customer_id; + }; /** * If the client has some money in his wallet & the price is not zero, then we should display this component. */ const shouldBeShown = (): boolean => { return wallet.amount > 0 && price > 0; - } + }; /** * If the amount in the wallet is not enough to cover the whole price, then the user must pay the remaining price * using another payment mean. */ const hasRemainingPrice = (): boolean => { return remainingPrice > 0; - } + }; /** * Does the current cart contains a payment schedule? */ const isPaymentSchedule = (): boolean => { return cart.items.find(i => 'subscription' in i) && cart.payment_schedule; - } + }; /** * Return the human-readable name of the item currently bought with the wallet */ @@ -74,15 +74,15 @@ export const WalletInfo: React.FC = ({ cart, currentUser, walle } return t(`app.shared.wallet.wallet_info.item_${item}`); - } + }; return (
{shouldBeShown() &&
{isOperatorAndClient() &&
-

{t('app.shared.wallet.wallet_info.you_have_AMOUNT_in_wallet', {AMOUNT: FormatLib.price(wallet.amount)})}

+

{t('app.shared.wallet.wallet_info.you_have_AMOUNT_in_wallet', { AMOUNT: FormatLib.price(wallet.amount) })}

{!hasRemainingPrice() &&

- {t('app.shared.wallet.wallet_info.wallet_pay_ITEM', {ITEM: getPriceItem()})} + {t('app.shared.wallet.wallet_info.wallet_pay_ITEM', { ITEM: getPriceItem() })}

} {hasRemainingPrice() &&

{t('app.shared.wallet.wallet_info.credit_AMOUNT_for_pay_ITEM', { @@ -92,9 +92,9 @@ export const WalletInfo: React.FC = ({ cart, currentUser, walle

}
} {!isOperatorAndClient() &&
-

{t('app.shared.wallet.wallet_info.client_have_AMOUNT_in_wallet', {AMOUNT: FormatLib.price(wallet.amount)})}

+

{t('app.shared.wallet.wallet_info.client_have_AMOUNT_in_wallet', { AMOUNT: FormatLib.price(wallet.amount) })}

{!hasRemainingPrice() &&

- {t('app.shared.wallet.wallet_info.client_wallet_pay_ITEM', {ITEM: getPriceItem()})} + {t('app.shared.wallet.wallet_info.client_wallet_pay_ITEM', { ITEM: getPriceItem() })}

} {hasRemainingPrice() &&

{t('app.shared.wallet.wallet_info.client_credit_AMOUNT_for_pay_ITEM', { @@ -110,7 +110,7 @@ export const WalletInfo: React.FC = ({ cart, currentUser, walle

}
); -} +}; const WalletInfoWrapper: React.FC = ({ currentUser, cart, price, wallet }) => { return ( @@ -118,6 +118,6 @@ const WalletInfoWrapper: React.FC = ({ currentUser, cart, price ); -} +}; Application.Components.component('walletInfo', react2angular(WalletInfoWrapper, ['currentUser', 'price', 'cart', 'wallet'])); diff --git a/app/frontend/src/javascript/models/payzen.ts b/app/frontend/src/javascript/models/payzen.ts index 94907ef9b..8cb7228b8 100644 --- a/app/frontend/src/javascript/models/payzen.ts +++ b/app/frontend/src/javascript/models/payzen.ts @@ -179,11 +179,9 @@ export interface KryptonConfig { } type DefaultCallback = () => void -// eslint-disable-next-line no-use-before-define type BrandChangedCallback = (event: { KR: KryptonClient, cardInfo: { brand: string } }) => void type ErrorCallback = (event: KryptonError) => void type FocusCallback = (event: KryptonFocus) => void -// eslint-disable-next-line no-use-before-define type InstallmentChangedCallback = (event: { KR: KryptonClient, installmentInfo: { brand: string, hasInterests: boolean, installmentCount: number, totalAmount: number } }) => void type SubmitCallback = (event: ProcessPaymentAnswer) => boolean type ClickCallback = (event: unknown) => boolean