From 94de0eb4c0b5fd172f1acc150aac85d16596cac9 Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Thu, 1 Jun 2023 14:20:55 -0500 Subject: [PATCH 01/15] Add translations for scheduling menu --- src/BursarExportPlugin.tsx | 5 +- src/form/ConfigurationForm.tsx | 7 ++- src/form/sections/SchedulingMenu.test.tsx | 4 +- src/form/sections/SchedulingMenu.tsx | 51 +++++++++++++++----- translations/ui-plugin-bursar-export/en.json | 47 +++++------------- 5 files changed, 63 insertions(+), 51 deletions(-) diff --git a/src/BursarExportPlugin.tsx b/src/BursarExportPlugin.tsx index a47dc6fd..30ae9be0 100644 --- a/src/BursarExportPlugin.tsx +++ b/src/BursarExportPlugin.tsx @@ -14,6 +14,7 @@ import useManualSchedulerMutation from './api/mutators/useManualSchedulerMutatio import ConfigurationForm, { FORM_ID } from './form/ConfigurationForm'; import useInitialValues from './hooks/useInitialValues'; import FormValues from './types/FormValues'; +import { FormattedMessage } from 'react-intl'; export default function BursarExportPlugin() { const stripes = useStripes(); @@ -39,7 +40,9 @@ export default function BursarExportPlugin() { if (initialValues === null) { return ( + } defaultWidth="fill" footer={ - + + } + > diff --git a/src/form/sections/SchedulingMenu.test.tsx b/src/form/sections/SchedulingMenu.test.tsx index 875fa68d..eb8e74ca 100644 --- a/src/form/sections/SchedulingMenu.test.tsx +++ b/src/form/sections/SchedulingMenu.test.tsx @@ -69,7 +69,7 @@ describe('Scheduling menu', () => { ).toBeVisible(); expect( screen.getByRole('textbox', { - name: (name) => name.startsWith('Run at'), + name: (name) => name.startsWith('Start time'), }) ).toBeVisible(); }); @@ -94,7 +94,7 @@ describe('Scheduling menu', () => { ).toBeVisible(); expect( screen.getByRole('textbox', { - name: (name) => name.startsWith('Run at'), + name: (name) => name.startsWith('Start time'), }) ).toBeVisible(); expect( diff --git a/src/form/sections/SchedulingMenu.tsx b/src/form/sections/SchedulingMenu.tsx index b110df59..2ed01002 100644 --- a/src/form/sections/SchedulingMenu.tsx +++ b/src/form/sections/SchedulingMenu.tsx @@ -9,18 +9,24 @@ import { } from '@folio/stripes/components'; import React from 'react'; import { Field, useField } from 'react-final-form'; -import { useIntl } from 'react-intl'; +import { FormattedMessage, useIntl } from 'react-intl'; import { Weekday, useLocaleWeekdays } from '../../utils/WeekdayUtils'; import SchedulingFrequency from '../../types/SchedulingFrequency'; export function getIntervalLabel(frequency: SchedulingFrequency) { switch (frequency) { case SchedulingFrequency.Hours: - return 'Hours between runs'; + return ( + + ); case SchedulingFrequency.Days: - return 'Days between runs'; + return ( + + ); case SchedulingFrequency.Weeks: - return 'Weeks between runs'; + return ( + + ); default: return ''; } @@ -31,7 +37,8 @@ export default function SchedulingMenu() { subscription: { value: true }, }).input.value; - const localeWeekdays = useLocaleWeekdays(useIntl()); + const intl = useIntl(); + const localeWeekdays = useLocaleWeekdays(intl); return ( @@ -45,22 +52,32 @@ export default function SchedulingMenu() { {...fieldProps} fullWidth required - label="Frequency" + label={ + + } dataOptions={[ { - label: 'Never (run manually)', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.scheduling.frequency.manual', + }), value: SchedulingFrequency.Manual, }, { - label: 'Hours', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.scheduling.frequency.hours', + }), value: SchedulingFrequency.Hours, }, { - label: 'Days', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.scheduling.frequency.days', + }), value: SchedulingFrequency.Days, }, { - label: 'Weeks', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.scheduling.frequency.weeks', + }), value: SchedulingFrequency.Weeks, }, ]} @@ -93,19 +110,27 @@ export default function SchedulingMenu() { {(fieldProps) => ( - + )} )} {frequencyValue === SchedulingFrequency.Weeks && ( - + {(fieldProps) => ( > {...fieldProps} required - label="Run on weekdays" + label={ + + } dataOptions={localeWeekdays.map((weekday) => ({ label: weekday.long, value: weekday.weekday, diff --git a/translations/ui-plugin-bursar-export/en.json b/translations/ui-plugin-bursar-export/en.json index 5d26a3f6..c3195fa7 100644 --- a/translations/ui-plugin-bursar-export/en.json +++ b/translations/ui-plugin-bursar-export/en.json @@ -1,40 +1,19 @@ { "meta.title": "Transfer criteria", - "bursarExports": "Bursar exports", - "bursarExports.schedulePeriod": "Schedule period", - "bursarExports.schedulePeriod.none": "None", - "bursarExports.schedulePeriod.hours": "Hours", - "bursarExports.schedulePeriod.days": "Days", - "bursarExports.schedulePeriod.weeks": "Weeks", - "bursarExports.scheduleFrequency": "Schedule frequency", - "bursarExports.scheduleWeekdays": "Weekdays", - "bursarExports.scheduleWeekdays.friday": "F", - "bursarExports.scheduleWeekdays.monday": "M", - "bursarExports.scheduleWeekdays.saturday": "S", - "bursarExports.scheduleWeekdays.sunday": "S", - "bursarExports.scheduleWeekdays.thursday": "T", - "bursarExports.scheduleWeekdays.tuesday": "T", - "bursarExports.scheduleWeekdays.wednesday": "W", - "bursarExports.scheduleTime": "Schedule time", - "bursarExports.daysOutstanding": "Fees/Fines older than (days)", - "bursarExports.patronGroups": "Patron groups", - "bursarExports.transferOwner": "Transfer owner", - "bursarExports.transferAccount": "Transfer account", - "bursarExports.owner": "Fee/fine owner", - "bursarExports.itemTypes": "Transfer types", - "bursarExports.feeFineType": "Fee/fine type", - "bursarExports.itemType": "Transfer type", - "bursarExports.itemDescription": "Transfer description", - "bursarExports.itemCode": "Transfer code", - "bursarExports.itemCode.CHARGE": "Charge", - "bursarExports.itemCode.PAYMENT": "Payment", - "bursarExports.save": "Save", - "bursarExports.save.success": "Bursar exports configuration has been successfully saved", - "bursarExports.save.error": "Bursar exports configuration was not saved", - "bursarExports.runManually": "Run manually", - "bursarExports.runManually.success": "Bursar exports has been successfully scheduled", - "bursarExports.runManually.error": "Bursar exports was not scheduled", + "bursarExports.paneTitle": "Transfer criteria", + + "bursarExports.scheduling.accordion": "Scheduling", + "bursarExports.scheduling.frequency": "Frequency", + "bursarExports.scheduling.frequency.manual": "Never (run manually)", + "bursarExports.scheduling.frequency.hours": "Hours", + "bursarExports.scheduling.frequency.days": "Days", + "bursarExports.scheduling.frequency.weeks": "Weeks", + "bursarExports.scheduling.interval.hours": "Hours between runs", + "bursarExports.scheduling.interval.days": "Days between runs", + "bursarExports.scheduling.interval.weeks": "Weeks between runs", + "bursarExports.scheduling.time": "Start time", + "bursarExports.scheduling.weekdays": "Run on weekdays", "permission.bursar-exports.all": "Transfer exports: Modify configuration and start jobs", "permission.bursar-exports.manual": "Transfer exports: Start manual jobs", From 710d164fdaae032abe0e1c37189ebc867646c228 Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Thu, 1 Jun 2023 14:23:26 -0500 Subject: [PATCH 02/15] Update title to 'transfer configuration' --- src/BursarExportPlugin.tsx | 4 +++- translations/ui-plugin-bursar-export/en.json | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/BursarExportPlugin.tsx b/src/BursarExportPlugin.tsx index 30ae9be0..808a73f7 100644 --- a/src/BursarExportPlugin.tsx +++ b/src/BursarExportPlugin.tsx @@ -91,7 +91,9 @@ export default function BursarExportPlugin() { /> } id="pane-batch-group-configuration" - paneTitle="Transfer configuration" + paneTitle={ + + } > Date: Thu, 15 Jun 2023 19:11:16 -0500 Subject: [PATCH 03/15] Add full localization and sort dropdowns and queries --- src/BursarExportPlugin.tsx | 4 +- .../AggregateCriteriaCard.tsx | 37 ++- src/components/Criteria/CriteriaAge.tsx | 5 +- src/components/Criteria/CriteriaAmount.tsx | 5 +- .../Criteria/CriteriaCardSelect.tsx | 65 +++-- .../Criteria/CriteriaFeeFineOwner.tsx | 9 +- .../Criteria/CriteriaFeeFineType.tsx | 21 +- src/components/Criteria/CriteriaLocation.tsx | 25 +- .../Criteria/CriteriaPatronGroup.tsx | 10 +- .../Criteria/CriteriaServicePoint.tsx | 10 +- src/components/Criteria/OperatorSelect.tsx | 22 +- .../Token/Data/AccountDateToken.tsx | 25 +- .../Token/Data/ConstantConditionalToken.tsx | 21 +- src/components/Token/Data/DataTypeSelect.tsx | 224 +++++++++++------- .../Token/Data/FeeFineTypeToken.tsx | 14 +- src/components/Token/Data/ItemInfoToken.tsx | 83 ++++--- src/components/Token/Data/UserInfoToken.tsx | 96 +++++--- .../Token/Data/UserItemInfoToken.tsx | 12 +- .../HeaderFooter/HeaderFooterTypeSelect.tsx | 126 ++++++---- .../Token/Shared/AmountWithDecimalToken.tsx | 11 +- .../Token/Shared/ArbitraryTextToken.tsx | 5 +- .../Token/Shared/DatePartPicker.tsx | 46 +++- .../Token/Shared/TimezonePicker.tsx | 8 +- .../Token/Shared/WhitespaceToken.tsx | 5 +- src/components/TransferAccountFields.tsx | 13 +- src/form/ConfigurationForm.tsx | 42 +++- src/form/sections/AggregateMenu.tsx | 14 +- src/form/sections/DataTokenMenu.tsx | 3 +- src/form/sections/ExportPreview.tsx | 22 +- src/form/sections/HeaderFooterMenu.tsx | 3 +- src/form/sections/TransferInfoMenu.tsx | 17 +- translations/ui-plugin-bursar-export/en.json | 130 ++++++++++ 32 files changed, 813 insertions(+), 320 deletions(-) diff --git a/src/BursarExportPlugin.tsx b/src/BursarExportPlugin.tsx index 808a73f7..ef836dab 100644 --- a/src/BursarExportPlugin.tsx +++ b/src/BursarExportPlugin.tsx @@ -72,7 +72,7 @@ export default function BursarExportPlugin() { formApiRef.current?.change('buttonClicked', 'manual') } > - Run manually + } renderEnd={ @@ -85,7 +85,7 @@ export default function BursarExportPlugin() { formApiRef.current?.change('buttonClicked', 'save') } > - Save + } /> diff --git a/src/components/AggregateCriteria/AggregateCriteriaCard.tsx b/src/components/AggregateCriteria/AggregateCriteriaCard.tsx index 8bae9dbd..f5cc6ab1 100644 --- a/src/components/AggregateCriteria/AggregateCriteriaCard.tsx +++ b/src/components/AggregateCriteria/AggregateCriteriaCard.tsx @@ -4,6 +4,7 @@ import { CriteriaAggregateType } from '../../types/CriteriaTypes'; import { Field, useField } from 'react-final-form'; import OperatorSelect from '../Criteria/OperatorSelect'; import useMonetaryOnBlur from '../../hooks/useMonetaryOnBlur'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function AggregateCriteriaCard() { const selectedType = useField('aggregateFilter.type', { @@ -12,9 +13,14 @@ export default function AggregateCriteriaCard() { }).input.value; const monetaryOnBlur = useMonetaryOnBlur('aggregateFilter.amountDollars'); + const intl = useIntl(); return ( - + + } + > + } dataOptions={[ { - label: 'None (include all patrons)', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.none', + }), value: CriteriaAggregateType.PASS, }, { - label: 'Number of accounts', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.numAccounts', + }), value: CriteriaAggregateType.NUM_ROWS, }, { - label: 'Total amount', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.totalAmount', + }), value: CriteriaAggregateType.TOTAL_AMOUNT, }, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} @@ -63,7 +77,9 @@ export default function AggregateCriteriaCard() { marginBottom0 required type="number" - label="Number of accounts" + label={ + + } min={1} step={1} /> @@ -82,7 +98,9 @@ export default function AggregateCriteriaCard() { marginBottom0 required type="number" - label="Amount" + label={ + + } min={0} step={0.01} onBlur={monetaryOnBlur} @@ -95,8 +113,7 @@ export default function AggregateCriteriaCard() {

- This will be applied after accounts are evaluated per the - “Criteria” specified above. +

diff --git a/src/components/Criteria/CriteriaAge.tsx b/src/components/Criteria/CriteriaAge.tsx index f1afd28c..504752dc 100644 --- a/src/components/Criteria/CriteriaAge.tsx +++ b/src/components/Criteria/CriteriaAge.tsx @@ -1,6 +1,7 @@ import { Col, TextField } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; +import { FormattedMessage } from 'react-intl'; export default function CriteriaAge({ prefix }: { prefix: string }) { return ( @@ -13,7 +14,9 @@ export default function CriteriaAge({ prefix }: { prefix: string }) { marginBottom0 required type="number" - label="Older than (days)" + label={ + + } min={1} step={1} /> diff --git a/src/components/Criteria/CriteriaAmount.tsx b/src/components/Criteria/CriteriaAmount.tsx index 23fa1acd..a239fd27 100644 --- a/src/components/Criteria/CriteriaAmount.tsx +++ b/src/components/Criteria/CriteriaAmount.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { Field } from 'react-final-form'; import useMonetaryOnBlur from '../../hooks/useMonetaryOnBlur'; import OperatorSelect from './OperatorSelect'; +import { FormattedMessage } from 'react-intl'; export default function CriteriaAmount({ prefix }: { prefix: string }) { const monetaryOnBlur = useMonetaryOnBlur(`${prefix}amountDollars`); @@ -21,7 +22,9 @@ export default function CriteriaAmount({ prefix }: { prefix: string }) { marginBottom0 required type="number" - label="Amount" + label={ + + } min={0} step={0.01} onBlur={monetaryOnBlur} diff --git a/src/components/Criteria/CriteriaCardSelect.tsx b/src/components/Criteria/CriteriaCardSelect.tsx index 2bec11bf..2f9d5dc5 100644 --- a/src/components/Criteria/CriteriaCardSelect.tsx +++ b/src/components/Criteria/CriteriaCardSelect.tsx @@ -5,6 +5,7 @@ import { CriteriaGroupType, CriteriaTerminalType, } from '../../types/CriteriaTypes'; +import { useIntl } from 'react-intl'; export default function CriteriaCardSelect({ name, @@ -23,20 +24,28 @@ export default function CriteriaCardSelect({ } }, [root]); + const intl = useIntl(); + const selectOptions = useMemo(() => { const options: SelectOptionType< CriteriaGroupType | CriteriaTerminalType >[] = [ { - label: 'All of:', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.allOf', + }), value: CriteriaGroupType.ALL_OF, }, { - label: 'Any of:', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.anyOf', + }), value: CriteriaGroupType.ANY_OF, }, { - label: 'None of:', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.noneOf', + }), value: CriteriaGroupType.NONE_OF, }, @@ -48,42 +57,66 @@ export default function CriteriaCardSelect({ // TODO: sort these alphabetically per i18n ...(patronOnly - ? [] + ? [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.patronGroup', + }), + value: CriteriaTerminalType.PATRON_GROUP, + }, + ] : [ { - label: 'Age', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.age', + }), value: CriteriaTerminalType.AGE, }, { - label: 'Amount', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.amount', + }), value: CriteriaTerminalType.AMOUNT, }, { - label: 'Fee/fine owner', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.owner', + }), value: CriteriaTerminalType.FEE_FINE_OWNER, }, { - label: 'Fee/fine type', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.type', + }), value: CriteriaTerminalType.FEE_FINE_TYPE, }, { - label: 'Item location', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.location', + }), value: CriteriaTerminalType.LOCATION, }, { - label: 'Item service point', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.servicePoint', + }), value: CriteriaTerminalType.SERVICE_POINT, }, - ]), - { - label: 'Patron group', - value: CriteriaTerminalType.PATRON_GROUP, - }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.patronGroup', + }), + value: CriteriaTerminalType.PATRON_GROUP, + }, + ] + ).sort((a, b) => a.label.localeCompare(b.label)), ]; if (root) { options.unshift({ - label: 'No criteria (always run)', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.select.none', + }), value: CriteriaTerminalType.PASS, }); } diff --git a/src/components/Criteria/CriteriaFeeFineOwner.tsx b/src/components/Criteria/CriteriaFeeFineOwner.tsx index a024f384..a3434434 100644 --- a/src/components/Criteria/CriteriaFeeFineOwner.tsx +++ b/src/components/Criteria/CriteriaFeeFineOwner.tsx @@ -2,6 +2,7 @@ import { Col, Select } from '@folio/stripes/components'; import React, { useMemo } from 'react'; import { Field } from 'react-final-form'; import useFeeFineOwners from '../../api/queries/useFeeFineOwners'; +import { FormattedMessage } from 'react-intl'; export default function CriteriaFeeFineOwner({ prefix }: { prefix: string }) { const feeFineOwners = useFeeFineOwners(); @@ -27,10 +28,14 @@ export default function CriteriaFeeFineOwner({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Fee/fine owner" + label={ + + } dataOptions={[ { label: '', value: '', disabled: true }, - ...ownersSelectOptions, + ...ownersSelectOptions.sort((a, b) => + a.label.localeCompare(b.label) + ), ]} /> )} diff --git a/src/components/Criteria/CriteriaFeeFineType.tsx b/src/components/Criteria/CriteriaFeeFineType.tsx index 330d487a..a7ca6bd1 100644 --- a/src/components/Criteria/CriteriaFeeFineType.tsx +++ b/src/components/Criteria/CriteriaFeeFineType.tsx @@ -3,10 +3,12 @@ import React, { useMemo } from 'react'; import { Field, useField } from 'react-final-form'; import useFeeFineOwners from '../../api/queries/useFeeFineOwners'; import useFeeFineTypes from '../../api/queries/useFeeFineTypes'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function CriteriaFeeFineType({ prefix }: { prefix: string }) { const feeFineOwners = useFeeFineOwners(); const feeFineTypes = useFeeFineTypes(); + const intl = useIntl(); const selectedOwner = useField( `${prefix}feeFineOwnerId`, @@ -60,11 +62,18 @@ export default function CriteriaFeeFineType({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Fee/fine owner" + label={ + + } dataOptions={[ - { label: 'Automatic', value: 'automatic' }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.criteria.type.automatic', + }), + value: 'automatic', + }, ...ownersSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )}
@@ -77,11 +86,13 @@ export default function CriteriaFeeFineType({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Fee/fine type" + label={ + + } dataOptions={[ { label: '', value: undefined }, ...typeSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )}
diff --git a/src/components/Criteria/CriteriaLocation.tsx b/src/components/Criteria/CriteriaLocation.tsx index e596721c..aeee14d9 100644 --- a/src/components/Criteria/CriteriaLocation.tsx +++ b/src/components/Criteria/CriteriaLocation.tsx @@ -5,6 +5,7 @@ import useCampuses from '../../api/queries/useCampuses'; import useInstitutions from '../../api/queries/useInstitutions'; import useLibraries from '../../api/queries/useLibraries'; import useLocations from '../../api/queries/useLocations'; +import { FormattedMessage } from 'react-intl'; export default function CriteriaLocation({ prefix }: { prefix: string }) { const institutions = useInstitutions(); @@ -85,11 +86,13 @@ export default function CriteriaLocation({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Institution" + label={ + + } dataOptions={[ { label: '', value: undefined }, ...institutionSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} @@ -102,11 +105,13 @@ export default function CriteriaLocation({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Campus" + label={ + + } dataOptions={[ { label: '', value: undefined }, ...campusSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} @@ -119,11 +124,13 @@ export default function CriteriaLocation({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Library" + label={ + + } dataOptions={[ { label: '', value: undefined }, ...librarySelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} @@ -136,11 +143,13 @@ export default function CriteriaLocation({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Location" + label={ + + } dataOptions={[ { label: '', value: undefined }, ...locationSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} diff --git a/src/components/Criteria/CriteriaPatronGroup.tsx b/src/components/Criteria/CriteriaPatronGroup.tsx index ca28cc4e..9284f1cb 100644 --- a/src/components/Criteria/CriteriaPatronGroup.tsx +++ b/src/components/Criteria/CriteriaPatronGroup.tsx @@ -2,6 +2,7 @@ import { Col, Select } from '@folio/stripes/components'; import React, { useMemo } from 'react'; import { Field } from 'react-final-form'; import usePatronGroups from '../../api/queries/usePatronGroups'; +import { FormattedMessage } from 'react-intl'; export default function CriteriaPatronGroup({ prefix }: { prefix: string }) { const patronGroups = usePatronGroups(); @@ -26,8 +27,13 @@ export default function CriteriaPatronGroup({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Patron group" - dataOptions={[{ label: '', value: undefined }, ...selectOptions]} + label={ + + } + dataOptions={[ + { label: '', value: undefined }, + ...selectOptions, + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} diff --git a/src/components/Criteria/CriteriaServicePoint.tsx b/src/components/Criteria/CriteriaServicePoint.tsx index 710da195..39ba8a25 100644 --- a/src/components/Criteria/CriteriaServicePoint.tsx +++ b/src/components/Criteria/CriteriaServicePoint.tsx @@ -2,6 +2,7 @@ import { Col, Select } from '@folio/stripes/components'; import React, { useMemo } from 'react'; import { Field } from 'react-final-form'; import useServicePoints from '../../api/queries/useServicePoints'; +import { FormattedMessage } from 'react-intl'; export default function CriteriaServicePoint({ prefix }: { prefix: string }) { const servicePoints = useServicePoints(); @@ -26,8 +27,13 @@ export default function CriteriaServicePoint({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Service point" - dataOptions={[{ label: '', value: undefined }, ...selectOptions]} + label={ + + } + dataOptions={[ + { label: '', value: undefined }, + ...selectOptions, + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} diff --git a/src/components/Criteria/OperatorSelect.tsx b/src/components/Criteria/OperatorSelect.tsx index b38c7836..5d6ba999 100644 --- a/src/components/Criteria/OperatorSelect.tsx +++ b/src/components/Criteria/OperatorSelect.tsx @@ -2,8 +2,10 @@ import { Select } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; import { ComparisonOperator } from '../../types/CriteriaTypes'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function OperatorSelect({ name }: { name: string }) { + const intl = useIntl(); return ( {(fieldProps) => ( @@ -12,23 +14,33 @@ export default function OperatorSelect({ name }: { name: string }) { fullWidth marginBottom0 required - label="Comparison operator" + label={ + + } dataOptions={[ { label: '', value: undefined }, { - label: 'Less than but not equal to', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.operator.less', + }), value: ComparisonOperator.LESS_THAN, }, { - label: 'Less than or equal to', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.operator.lessEqual', + }), value: ComparisonOperator.LESS_THAN_EQUAL, }, { - label: 'Greater than but not equal to', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.operator.greater', + }), value: ComparisonOperator.GREATER_THAN, }, { - label: 'Greater than or equal to', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.operator.greaterEqual', + }), value: ComparisonOperator.GREATER_THAN_EQUAL, }, ]} diff --git a/src/components/Token/Data/AccountDateToken.tsx b/src/components/Token/Data/AccountDateToken.tsx index 2349c54b..5202e761 100644 --- a/src/components/Token/Data/AccountDateToken.tsx +++ b/src/components/Token/Data/AccountDateToken.tsx @@ -3,8 +3,10 @@ import React from 'react'; import { Field } from 'react-final-form'; import DatePartPicker from '../Shared/DatePartPicker'; import TimezonePicker from '../Shared/TimezonePicker'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function AccountDateToken({ prefix }: { prefix: string }) { + const intl = useIntl(); return ( <> @@ -19,19 +21,27 @@ export default function AccountDateToken({ prefix }: { prefix: string }) { label="Date" dataOptions={[ { - label: 'Creation date', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountDate.dateType.created', + }), value: 'CREATED', }, { - label: 'Last updated date', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountDate.dateType.updated', + }), value: 'UPDATED', }, { - label: 'Item due date', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountDate.dateType.dueItem', + }), value: 'DUE', }, { - label: 'Loan end date', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountDate.dateType.dueLoan', + }), value: 'DUE', }, ]} @@ -48,7 +58,9 @@ export default function AccountDateToken({ prefix }: { prefix: string }) { {...fieldProps} fullWidth - label="Fallback value" + label={ + + } /> )} @@ -59,8 +71,7 @@ export default function AccountDateToken({ prefix }: { prefix: string }) {

- If the chosen date is not available/applicable, the fallback value - will be used instead. +

diff --git a/src/components/Token/Data/ConstantConditionalToken.tsx b/src/components/Token/Data/ConstantConditionalToken.tsx index 3321393c..3c7eae55 100644 --- a/src/components/Token/Data/ConstantConditionalToken.tsx +++ b/src/components/Token/Data/ConstantConditionalToken.tsx @@ -9,6 +9,7 @@ import { CriteriaTerminal, } from '../../../types/CriteriaTypes'; import ConditionalCard from '../../ConditionalCard'; +import { FormattedMessage } from 'react-intl'; export default function ConstantConditionalToken({ prefix, @@ -42,7 +43,9 @@ export default function ConstantConditionalToken({ {...fieldProps} fullWidth required - label="Then use:" + label={ + + } /> )} @@ -50,14 +53,20 @@ export default function ConstantConditionalToken({ ))} - + + } + > {(fieldProps) => ( {...fieldProps} fullWidth required - label="Fallback value" + label={ + + } /> )} @@ -67,13 +76,11 @@ export default function ConstantConditionalToken({

- Conditions will be evaluated in order, with the first matched - value being used. If no conditions are matched, the fallback - value will be used. +

diff --git a/src/components/Token/Data/DataTypeSelect.tsx b/src/components/Token/Data/DataTypeSelect.tsx index 7f42e505..d62abe86 100644 --- a/src/components/Token/Data/DataTypeSelect.tsx +++ b/src/components/Token/Data/DataTypeSelect.tsx @@ -1,96 +1,149 @@ import { Select } from '@folio/stripes/components'; -import React from 'react'; +import React, { useMemo } from 'react'; import { Field, useField } from 'react-final-form'; import { DataTokenType } from '../../../types/TokenTypes'; +import { useIntl } from 'react-intl'; -const ALWAYS_AVAILABLE_OPTIONS = [ - { - label: 'Newline (LF)', - value: DataTokenType.NEWLINE, - }, - { - label: 'Newline (Microsoft, CRLF)', - value: DataTokenType.NEWLINE_MICROSOFT, - }, - { - label: 'Tab', - value: DataTokenType.TAB, - }, - { - label: 'Comma', - value: DataTokenType.COMMA, - }, - { - label: 'Whitespace', - value: DataTokenType.SPACE, - }, - - { - label: '', - value: DataTokenType.NEWLINE, - disabled: true, - }, +export default function DataTypeSelect({ name }: { name: string }) { + const isAggregate = useField('aggregate', { + subscription: { value: true }, + format: (value) => value ?? false, + }).input.value; - { - label: 'Arbitrary text', - value: DataTokenType.ARBITRARY_TEXT, - }, - { - label: 'Current date', - value: DataTokenType.CURRENT_DATE, - }, - { - label: 'Conditional text', - value: DataTokenType.CONSTANT_CONDITIONAL, - }, + const intl = useIntl(); - { - label: '', - value: DataTokenType.NEWLINE, - disabled: true, - }, + const alwaysAvailableOptions = useMemo(() => { + const topOptions = [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.newline', + }), + value: DataTokenType.NEWLINE, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.newlineMicrosoft', + }), + value: DataTokenType.NEWLINE_MICROSOFT, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.tab', + }), + value: DataTokenType.TAB, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.comma', + }), + value: DataTokenType.COMMA, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.whitespace', + }), + value: DataTokenType.SPACE, + }, + ].sort((a, b) => a.label.localeCompare(b.label)); - { - label: 'User info', - value: DataTokenType.USER_DATA, - }, -]; + const bottomOptions = [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.arbitraryText', + }), + value: DataTokenType.ARBITRARY_TEXT, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate', + }), + value: DataTokenType.CURRENT_DATE, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.constantConditional', + }), + value: DataTokenType.CONSTANT_CONDITIONAL, + }, + ].sort((a, b) => a.label.localeCompare(b.label)); -const NON_AGGREGATE_OPTIONS = [ - { - label: 'Account amount', - value: DataTokenType.ACCOUNT_AMOUNT, - }, - { - label: 'Account date', - value: DataTokenType.ACCOUNT_DATE, - }, - { - label: 'Fee/fine type', - value: DataTokenType.FEE_FINE_TYPE, - }, - { - label: 'Item info', - value: DataTokenType.ITEM_INFO, - }, -]; + return [ + ...topOptions, + { + label: '', + value: DataTokenType.NEWLINE, + disabled: true, + }, + ...bottomOptions, + { + label: '', + value: DataTokenType.NEWLINE, + disabled: true, + }, + ]; + }, [intl]); -const AGGREGATE_OPTIONS = [ - { - label: 'Total amount', - value: DataTokenType.AGGREGATE_TOTAL, - }, - { - label: 'Number of accounts', - value: DataTokenType.AGGREGATE_COUNT, - }, -]; + const noneAggregateOptions = useMemo( + () => + [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userData', + }), + value: DataTokenType.USER_DATA, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountAmount', + }), + value: DataTokenType.ACCOUNT_AMOUNT, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountDate', + }), + value: DataTokenType.ACCOUNT_DATE, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.feeFineType', + }), + value: DataTokenType.FEE_FINE_TYPE, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo', + }), + value: DataTokenType.ITEM_INFO, + }, + ].sort((a, b) => a.label.localeCompare(b.label)), + [intl] + ); -export default function DataTypeSelect({ name }: { name: string }) { - const isAggregate = useField('aggregate', { - subscription: { value: true }, - format: (value) => value ?? false, - }).input.value; + const aggregateOptions = useMemo( + () => + [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userData', + }), + value: DataTokenType.USER_DATA, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.totalAmount', + }), + value: DataTokenType.AGGREGATE_TOTAL, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.numAccounts', + }), + value: DataTokenType.AGGREGATE_COUNT, + }, + ].sort((a, b) => a.label.localeCompare(b.label)), + [intl] + ); return ( @@ -100,9 +153,8 @@ export default function DataTypeSelect({ name }: { name: string }) { required marginBottom0 dataOptions={[ - // TODO: sort these alphabetically per i18n - ...ALWAYS_AVAILABLE_OPTIONS, - ...(isAggregate ? AGGREGATE_OPTIONS : NON_AGGREGATE_OPTIONS), + ...alwaysAvailableOptions, + ...(isAggregate ? aggregateOptions : noneAggregateOptions), ]} /> )} diff --git a/src/components/Token/Data/FeeFineTypeToken.tsx b/src/components/Token/Data/FeeFineTypeToken.tsx index 9a546dcc..d1522c5c 100644 --- a/src/components/Token/Data/FeeFineTypeToken.tsx +++ b/src/components/Token/Data/FeeFineTypeToken.tsx @@ -1,8 +1,10 @@ import { Col, Select } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function FeeFineTypeToken({ prefix }: { prefix: string }) { + const intl = useIntl(); return ( @@ -14,14 +16,20 @@ export default function FeeFineTypeToken({ prefix }: { prefix: string }) { {...fieldProps} required marginBottom0 - label="Attribute" + label={ + + } dataOptions={[ { - label: 'Type name', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.feeFineType.name', + }), value: 'FEE_FINE_TYPE_NAME', }, { - label: 'Type ID', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.feeFineType.id', + }), value: 'FEE_FINE_TYPE_ID', }, ]} diff --git a/src/components/Token/Data/ItemInfoToken.tsx b/src/components/Token/Data/ItemInfoToken.tsx index 6c55bdbe..8fa39e9d 100644 --- a/src/components/Token/Data/ItemInfoToken.tsx +++ b/src/components/Token/Data/ItemInfoToken.tsx @@ -1,43 +1,64 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { ItemAttribute } from '../../../types/TokenTypes'; import UserItemInfoToken from './UserItemInfoToken'; +import { useIntl } from 'react-intl'; export default function ItemInfoToken({ prefix }: { prefix: string }) { + const intl = useIntl(); + const options = useMemo(() => { + const selectOptions = [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.name', + }), + value: 'NAME' as ItemAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.barcode', + }), + value: 'BARCODE' as ItemAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.material', + }), + value: 'MATERIAL_TYPE' as ItemAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.instId', + }), + value: 'INSTITUTION_ID' as ItemAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.campId', + }), + value: 'CAMPUS_ID' as ItemAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.libId', + }), + value: 'LIBRARY_ID' as ItemAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.locId', + }), + value: 'LOCATION_ID' as ItemAttribute, + }, + ].sort((a, b) => a.label.localeCompare(b.label)); + return selectOptions; + }, [intl]); + return ( prefix={prefix} defaultValue="NAME" attributeName="itemAttribute" - options={[ - { - label: 'Name', - value: 'NAME', - }, - { - label: 'Barcode', - value: 'BARCODE', - }, - { - label: 'Material type', - value: 'MATERIAL_TYPE', - }, - { - label: 'Institution ID', - value: 'INSTITUTION_ID', - }, - { - label: 'Campus ID', - value: 'CAMPUS_ID', - }, - { - label: 'Library ID', - value: 'LIBRARY_ID', - }, - { - label: 'Location ID', - value: 'LOCATION_ID', - }, - ]} + options={options} /> ); } diff --git a/src/components/Token/Data/UserInfoToken.tsx b/src/components/Token/Data/UserInfoToken.tsx index fbe21ed2..1b0f682b 100644 --- a/src/components/Token/Data/UserInfoToken.tsx +++ b/src/components/Token/Data/UserInfoToken.tsx @@ -1,47 +1,71 @@ -import React from 'react'; -import { UserAttribute } from '../../../types/TokenTypes'; +import React, { useMemo } from 'react'; import UserItemInfoToken from './UserItemInfoToken'; +import { useIntl } from 'react-intl'; +import { UserAttribute } from '../../../types/TokenTypes'; export default function UserInfoToken({ prefix }: { prefix: string }) { + const intl = useIntl(); + + const options = useMemo(() => { + const selectOptions = [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.folioId', + }), + value: 'FOLIO_ID' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.extId', + }), + value: 'EXTERNAL_SYSTEM_ID' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.groupId', + }), + value: 'PATRON_GROUP_ID' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.barcode', + }), + value: 'BARCODE' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.username', + }), + value: 'USERNAME' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.firstname', + }), + value: 'FIRST_NAME' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.middlename', + }), + value: 'MIDDLE_NAME' as UserAttribute, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.lastname', + }), + value: 'LAST_NAME' as UserAttribute, + }, + ]; + return selectOptions; + }, [intl]); + return ( prefix={prefix} defaultValue="EXTERNAL_SYSTEM_ID" attributeName="userAttribute" - options={[ - { - label: 'Folio ID', - value: 'FOLIO_ID', - }, - { - label: 'External system ID', - value: 'EXTERNAL_SYSTEM_ID', - }, - { - label: 'Patron group ID', - value: 'PATRON_GROUP_ID', - }, - { - label: 'Barcode', - value: 'BARCODE', - }, - { - label: 'Username', - value: 'USERNAME', - }, - { - label: 'First name', - value: 'FIRST_NAME', - }, - { - label: 'Middle name', - value: 'MIDDLE_NAME', - }, - { - label: 'Last name', - value: 'LAST_NAME', - }, - ]} + options={options} /> ); } diff --git a/src/components/Token/Data/UserItemInfoToken.tsx b/src/components/Token/Data/UserItemInfoToken.tsx index 1339c462..75c54320 100644 --- a/src/components/Token/Data/UserItemInfoToken.tsx +++ b/src/components/Token/Data/UserItemInfoToken.tsx @@ -7,6 +7,7 @@ import { import React from 'react'; import { Field } from 'react-final-form'; import { ItemAttribute, UserAttribute } from '../../../types/TokenTypes'; +import { FormattedMessage } from 'react-intl'; export default function UserItemInfoToken< T extends ItemAttribute | UserAttribute @@ -32,7 +33,9 @@ export default function UserItemInfoToken< {...fieldProps} required - label="Value" + label={ + + } dataOptions={options} /> )} @@ -44,7 +47,9 @@ export default function UserItemInfoToken< {...fieldProps} fullWidth - label="Fallback value" + label={ + + } /> )} @@ -52,8 +57,7 @@ export default function UserItemInfoToken<

- If the chosen value is not available/applicable, the fallback value - will be used instead. +

diff --git a/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx b/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx index f760562a..406089fa 100644 --- a/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx +++ b/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx @@ -1,9 +1,86 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { HeaderFooterTokenType } from '../../../types/TokenTypes'; import { Select } from '@folio/stripes/components'; import { Field } from 'react-final-form'; +import { useIntl } from 'react-intl'; export default function HeaderFooterTypeSelect({ name }: { name: string }) { + const intl = useIntl(); + const options = useMemo(() => { + const topSection = [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.newline', + }), + value: HeaderFooterTokenType.NEWLINE, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.newlineMicrosoft', + }), + value: HeaderFooterTokenType.NEWLINE_MICROSOFT, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.tab', + }), + value: HeaderFooterTokenType.TAB, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.comma', + }), + value: HeaderFooterTokenType.COMMA, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.whitespace', + }), + value: HeaderFooterTokenType.SPACE, + }, + ]; + + const bottomSection = [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.arbitraryText', + }), + value: HeaderFooterTokenType.ARBITRARY_TEXT, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate', + }), + value: HeaderFooterTokenType.CURRENT_DATE, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.numAccounts', + }), + value: HeaderFooterTokenType.AGGREGATE_COUNT, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.totalAmount', + }), + value: HeaderFooterTokenType.AGGREGATE_TOTAL, + }, + ]; + + topSection.sort((a, b) => a.label.localeCompare(b.label)); + bottomSection.sort((a, b) => a.label.localeCompare(b.label)); + + return [ + ...topSection, + { + label: '', + value: HeaderFooterTokenType.NEWLINE, + disabled: true, + }, + ...bottomSection, + ]; + }, [intl]); + return ( {(fieldProps) => ( @@ -11,52 +88,7 @@ export default function HeaderFooterTypeSelect({ name }: { name: string }) { {...fieldProps} required marginBottom0 - dataOptions={[ - // TODO: sort these alphabetically per i18n - { - label: 'Newline (LF)', - value: HeaderFooterTokenType.NEWLINE, - }, - { - label: 'Newline (Microsoft, CRLF)', - value: HeaderFooterTokenType.NEWLINE_MICROSOFT, - }, - { - label: 'Tab', - value: HeaderFooterTokenType.TAB, - }, - { - label: 'Comma', - value: HeaderFooterTokenType.COMMA, - }, - { - label: 'Whitespace', - value: HeaderFooterTokenType.SPACE, - }, - - { - label: '', - value: HeaderFooterTokenType.NEWLINE, - disabled: true, - }, - - { - label: 'Arbitrary text', - value: HeaderFooterTokenType.ARBITRARY_TEXT, - }, - { - label: 'Current date', - value: HeaderFooterTokenType.CURRENT_DATE, - }, - { - label: 'Number of accounts', - value: HeaderFooterTokenType.AGGREGATE_COUNT, - }, - { - label: 'Total amount', - value: HeaderFooterTokenType.AGGREGATE_TOTAL, - }, - ]} + dataOptions={options} /> )} diff --git a/src/components/Token/Shared/AmountWithDecimalToken.tsx b/src/components/Token/Shared/AmountWithDecimalToken.tsx index 6be3ec69..a475729c 100644 --- a/src/components/Token/Shared/AmountWithDecimalToken.tsx +++ b/src/components/Token/Shared/AmountWithDecimalToken.tsx @@ -1,8 +1,10 @@ import { Checkbox, Col } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; +import { useIntl } from 'react-intl'; export default function AmountWithDecimalToken({ prefix }: { prefix: string }) { + const intl = useIntl(); return ( @@ -10,14 +12,17 @@ export default function AmountWithDecimalToken({ prefix }: { prefix: string }) { )}

- If selected, amounts will be exported like “12.50”; if - left unselected, they will be exported like “1250”. + {intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.accountAmount.enableDecimal.description', + })}

diff --git a/src/components/Token/Shared/ArbitraryTextToken.tsx b/src/components/Token/Shared/ArbitraryTextToken.tsx index 240f5021..16c9c0a4 100644 --- a/src/components/Token/Shared/ArbitraryTextToken.tsx +++ b/src/components/Token/Shared/ArbitraryTextToken.tsx @@ -1,6 +1,7 @@ import { Col, TextField } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; +import { FormattedMessage } from 'react-intl'; export default function ArbitraryTextToken({ prefix }: { prefix: string }) { return ( @@ -12,7 +13,9 @@ export default function ArbitraryTextToken({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Value" + label={ + + } /> )} diff --git a/src/components/Token/Shared/DatePartPicker.tsx b/src/components/Token/Shared/DatePartPicker.tsx index d0dacdab..7aa072f5 100644 --- a/src/components/Token/Shared/DatePartPicker.tsx +++ b/src/components/Token/Shared/DatePartPicker.tsx @@ -2,8 +2,10 @@ import { Select } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; import { DateFormatType } from '../../../types/TokenTypes'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function DatePartPicker({ prefix }: { prefix: string }) { + const intl = useIntl(); return ( {(fieldProps) => ( @@ -11,47 +13,69 @@ export default function DatePartPicker({ prefix }: { prefix: string }) { {...fieldProps} required marginBottom0 - label="Format" + label={ + + } dataOptions={[ { - label: 'Year (4-digit)', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.yearLong', + }), value: DateFormatType.YEAR_LONG, }, { - label: 'Year (2-digit)', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.yearShort', + }), value: DateFormatType.YEAR_SHORT, }, { - label: 'Month', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.month', + }), value: DateFormatType.MONTH, }, { - label: 'Day of month', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.date', + }), value: DateFormatType.DATE, }, { - label: 'Hour', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.hour', + }), value: DateFormatType.HOUR, }, { - label: 'Minute', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.minute', + }), value: DateFormatType.MINUTE, }, { - label: 'Second', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.second', + }), value: DateFormatType.SECOND, }, { - label: 'Quarter', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.quarter', + }), value: DateFormatType.QUARTER, }, { - label: 'ISO week number', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.isoWeekNum', + }), value: DateFormatType.WEEK_OF_YEAR_ISO, }, { - label: 'ISO week year', + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.token.currentDate.format.isoWeekYear', + }), value: DateFormatType.WEEK_YEAR_ISO, }, ]} diff --git a/src/components/Token/Shared/TimezonePicker.tsx b/src/components/Token/Shared/TimezonePicker.tsx index 4d879721..b13222d1 100644 --- a/src/components/Token/Shared/TimezonePicker.tsx +++ b/src/components/Token/Shared/TimezonePicker.tsx @@ -1,7 +1,7 @@ import { Select } from '@folio/stripes/components'; import React, { useMemo } from 'react'; -import { Field } from 'react-final-form'; -import { useIntl } from 'react-intl'; +import { Field, Form } from 'react-final-form'; +import { FormattedMessage, useIntl } from 'react-intl'; import timeZones from '../../../utils/timezones'; export default function TimezonePicker({ prefix }: { prefix: string }) { @@ -19,7 +19,9 @@ export default function TimezonePicker({ prefix }: { prefix: string }) { {...fieldProps} required marginBottom0 - label="Timezone" + label={ + + } dataOptions={timeZonesForSelect} /> )} diff --git a/src/components/Token/Shared/WhitespaceToken.tsx b/src/components/Token/Shared/WhitespaceToken.tsx index 0909b987..02f6a0fd 100644 --- a/src/components/Token/Shared/WhitespaceToken.tsx +++ b/src/components/Token/Shared/WhitespaceToken.tsx @@ -1,6 +1,7 @@ import { Col, TextField } from '@folio/stripes/components'; import React from 'react'; import { Field } from 'react-final-form'; +import { FormattedMessage } from 'react-intl'; export default function WhitespaceToken({ prefix }: { prefix: string }) { return ( @@ -14,7 +15,9 @@ export default function WhitespaceToken({ prefix }: { prefix: string }) { required type="number" min={1} - label="Number of spaces" + label={ + + } /> )} diff --git a/src/components/TransferAccountFields.tsx b/src/components/TransferAccountFields.tsx index 42dc3aad..a27589c2 100644 --- a/src/components/TransferAccountFields.tsx +++ b/src/components/TransferAccountFields.tsx @@ -3,6 +3,7 @@ import React, { useMemo } from 'react'; import { Field, useField } from 'react-final-form'; import useFeeFineOwners from '../api/queries/useFeeFineOwners'; import useTransferAccounts from '../api/queries/useTransferAccounts'; +import { FormattedMessage } from 'react-intl'; export default function TransferAccountFields({ prefix }: { prefix: string }) { const feeFineOwners = useFeeFineOwners(); @@ -48,11 +49,13 @@ export default function TransferAccountFields({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Fee/fine owner" + label={ + + } dataOptions={[ { label: '', value: undefined, disabled: true }, ...ownersSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} @@ -65,11 +68,13 @@ export default function TransferAccountFields({ prefix }: { prefix: string }) { fullWidth marginBottom0 required - label="Transfer account" + label={ + + } dataOptions={[ { label: '', value: undefined }, ...accountSelectOptions, - ]} + ].sort((a, b) => a.label.localeCompare(b.label))} /> )} diff --git a/src/form/ConfigurationForm.tsx b/src/form/ConfigurationForm.tsx index b4373a6f..8c737210 100644 --- a/src/form/ConfigurationForm.tsx +++ b/src/form/ConfigurationForm.tsx @@ -73,31 +73,59 @@ function ConfigurationForm({ >
- + + } + > - + + } + > - + + } + > + ) : ( + + ) } > - + + } + > - + + } + > - + + } + > diff --git a/src/form/sections/AggregateMenu.tsx b/src/form/sections/AggregateMenu.tsx index d26b57ee..23fb6413 100644 --- a/src/form/sections/AggregateMenu.tsx +++ b/src/form/sections/AggregateMenu.tsx @@ -2,6 +2,7 @@ import { Checkbox } from '@folio/stripes/components'; import React from 'react'; import { Field, useField } from 'react-final-form'; import AggregateCriteriaCard from '../../components/AggregateCriteria/AggregateCriteriaCard'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function AggregateMenu() { const isAggregateEnabled = useField('aggregate', { @@ -9,17 +10,24 @@ export default function AggregateMenu() { format: (value) => value ?? false, }).input.value; + const intl = useIntl(); + return (
{(fieldProps) => ( - + )}

- If enabled, each output row will correspond to a single patron with - all of their accounts, rather than just a single account. +

diff --git a/src/form/sections/DataTokenMenu.tsx b/src/form/sections/DataTokenMenu.tsx index 9bf47077..559c6ec1 100644 --- a/src/form/sections/DataTokenMenu.tsx +++ b/src/form/sections/DataTokenMenu.tsx @@ -4,6 +4,7 @@ import { FieldArray } from 'react-final-form-arrays'; import DataTokenCard from '../../components/Token/Data/DataTokenCard'; import { DataTokenType } from '../../types/TokenTypes'; import { useField } from 'react-final-form'; +import { FormattedMessage } from 'react-intl'; export default function DataTokenMenu() { const aggregate = useField('aggregate', { @@ -32,7 +33,7 @@ export default function DataTokenMenu() { /> ))} )} diff --git a/src/form/sections/ExportPreview.tsx b/src/form/sections/ExportPreview.tsx index 8a0369e3..175d6820 100644 --- a/src/form/sections/ExportPreview.tsx +++ b/src/form/sections/ExportPreview.tsx @@ -4,6 +4,7 @@ import { Card, Checkbox } from '@folio/stripes/components'; import classNames from 'classnames'; import { Field, useField } from 'react-final-form'; import ExportPreviewData from '../../components/ExportPreview/ExportPreviewData'; +import { FormattedMessage, useIntl } from 'react-intl'; export default function ExportPreview() { const wrap = useField('preview.wrap', { @@ -11,23 +12,32 @@ export default function ExportPreview() { format: (value) => value ?? true, }).input.value; + const intl = useIntl(); + return ( <> + } bodyClass={classNames(css.preview, { [css.wrap]: wrap })} >

- This preview is only a sample and does not represent real data, nor - does it consider any specified criteria. +

{(fieldProps) => ( - + )} @@ -35,7 +45,9 @@ export default function ExportPreview() { )} diff --git a/src/form/sections/HeaderFooterMenu.tsx b/src/form/sections/HeaderFooterMenu.tsx index de99d6c7..122a85da 100644 --- a/src/form/sections/HeaderFooterMenu.tsx +++ b/src/form/sections/HeaderFooterMenu.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { FieldArray } from 'react-final-form-arrays'; import { HeaderFooterTokenType } from '../../types/TokenTypes'; import HeaderFooterCard from '../../components/Token/HeaderFooter/HeaderFooterCard'; +import { FormattedMessage } from 'react-intl'; export default function HeaderFooterMenu({ name }: { name: string }) { return ( @@ -21,7 +22,7 @@ export default function HeaderFooterMenu({ name }: { name: string }) { )} diff --git a/src/form/sections/TransferInfoMenu.tsx b/src/form/sections/TransferInfoMenu.tsx index e383cea5..4f40acaf 100644 --- a/src/form/sections/TransferInfoMenu.tsx +++ b/src/form/sections/TransferInfoMenu.tsx @@ -4,6 +4,7 @@ import { FieldArray } from 'react-final-form-arrays'; import ConditionalCard from '../../components/ConditionalCard'; import TransferAccountFields from '../../components/TransferAccountFields'; import { CriteriaTerminalType } from '../../types/CriteriaTypes'; +import { FormattedMessage } from 'react-intl'; export default function TransferInfoMenu() { return ( @@ -21,7 +22,15 @@ export default function TransferInfoMenu() { ))} - + + ) : ( + + ) + } + > @@ -32,14 +41,12 @@ export default function TransferInfoMenu() { }) } > - Add condition +

- Conditions will be evaluated in order, with the first matched - transfer account being used. If no conditions are matched, the - account listed under “otherwise” will be used. +

diff --git a/translations/ui-plugin-bursar-export/en.json b/translations/ui-plugin-bursar-export/en.json index f3c38b82..022d3c64 100644 --- a/translations/ui-plugin-bursar-export/en.json +++ b/translations/ui-plugin-bursar-export/en.json @@ -3,6 +3,12 @@ "bursarExports.paneTitle": "Transfer configuration", + "bursarExports.button.addCondition": "Add condition", + "bursarExports.button.add": "Add", + "bursarExports.button.save": "Save", + "bursarExports.button.runManually": "Run manually", + "bursarExports.otherwise": "Otherwise:", + "bursarExports.scheduling.accordion": "Scheduling", "bursarExports.scheduling.frequency": "Frequency", "bursarExports.scheduling.frequency.manual": "Never (run manually)", @@ -15,6 +21,130 @@ "bursarExports.scheduling.time": "Start time", "bursarExports.scheduling.weekdays": "Run on weekdays", + "bursarExports.criteria.accordion": "Criteria", + "bursarExports.criteria.select.allOf": "All of", + "bursarExports.criteria.select.anyOf": "Any of", + "bursarExports.criteria.select.noneOf": "None of", + "bursarExports.criteria.select.age": "Age", + "bursarExports.criteria.select.amount": "Amount", + "bursarExports.criteria.select.owner": "Fee/fine owner", + "bursarExports.criteria.select.type": "Fee/fine type", + "bursarExports.criteria.select.location": "Item location", + "bursarExports.criteria.select.servicePoint": "Item service point", + "bursarExports.criteria.select.patronGroup": "Patron group", + "bursarExports.criteria.select.none": "No criteria (alwyays run)", + + "bursarExports.criteria.age.value": "Older than (days)", + "bursarExports.criteria.type.automatic": "Automatic", + "bursarExports.criteria.location.inst": "Institution", + "bursarExports.criteria.location.camp": "Campus", + "bursarExports.criteria.location.lib": "Library", + "bursarExports.criteria.location.loc": "Location", + "bursarExports.criteria.servicePoint.value": "Service point", + + "bursarExports.aggregate.accordion": "Aggregate by patron", + "bursarExports.aggregate.enabler": "Group data by patron", + "bursarExports.aggregate.description": "If enabled, each output row will correspond to a single patron with all of their accounts, rather than just a single account.", + "bursarExports.aggregate.filter": "Filter type", + "bursarExports.aggregate.filter.header": "Only include patrons with:", + "bursarExports.aggregate.filter.none": "None (include all patrons)", + "bursarExports.aggregate.filter.numAccounts": "Number of accounts", + "bursarExports.aggregate.filter.numAccounts.amount": "Number of accounts", + "bursarExports.aggregate.filter.totalAmount": "Total amount", + "bursarExports.aggregate.filter.totalAmount.amount": "Amount", + "bursarExports.aggregate.filter.operator": "Comparison operator", + "bursarExports.aggregate.filter.operator.less": "Less than but not equal to", + "bursarExports.aggregate.filter.operator.lessEqual": "Less than or equal to", + "bursarExports.aggregate.filter.operator.greater": "Greater than but not equal to", + "bursarExports.aggregate.filter.operator.greaterEqual": "Greater than or equal to", + "bursarExports.aggregate.filter.description": "This will be applied after accounts are evaluated per the \"Criteria\" specified above.", + + "bursarExports.header.accordion": "Header format", + "bursarExports.footer.accordion": "Footer format", + + "bursarExports.token.newline": "Newline (LF)", + "bursarExports.token.newlineMicrosoft": "Newline (Microsoft, CRLF)", + "bursarExports.token.tab": "Tab", + "bursarExports.token.comma": "Comma", + "bursarExports.token.whitespace": "Whitespace", + "bursarExports.token.arbitraryText": "Arbitrary text", + "bursarExports.token.currentDate": "Current date", + "bursarExports.token.constantConditional": "Conditional text", + "bursarExports.token.numAccounts": "Number of accounts", + "bursarExports.token.totalAmount": "Total amount", + "bursarExports.token.userData": "User info", + "bursarExports.token.accountAmount": "Account amount", + "bursarExports.token.accountDate": "Account date", + "bursarExports.token.feeFineType": "Fee/fine type", + "bursarExports.token.itemInfo": "Item info", + "bursarExports.token.fallback": "Fallback value", + "bursarExports.token.fallback.description": "If the chosen date is not available/applicable, the fallback value will be used instead.", + "bursarExports.token.value": "Value", + + "bursarExports.token.whitespace.numSpaces": "Number of spaces", + + "bursarExports.token.currentDate.format": "Format", + "bursarExports.token.currentDate.format.yearLong": "Year (4-digit)", + "bursarExports.token.currentDate.format.yearShort": "Year (2-digit)", + "bursarExports.token.currentDate.format.month": "Month", + "bursarExports.token.currentDate.format.date": "Day of month", + "bursarExports.token.currentDate.format.hour": "Hour", + "bursarExports.token.currentDate.format.minute": "Minute", + "bursarExports.token.currentDate.format.second": "Second", + "bursarExports.token.currentDate.format.quarter": "Quarter", + "bursarExports.token.currentDate.format.isoWeekNum": "ISO week number", + "bursarExports.token.currentDate.format.isoWeekYear": "ISO week year", + "bursarExports.token.currentDate.timezone": "Timezone", + + "bursarExports.token.accountAmount.enableDecimal": "Include the decimal point", + "bursarExports.token.accountAmount.enableDecimal.description": "If selected, amounts will be exported like \"12.50\" if left unselected, they will be exported like \"1250\".", + + "bursarExports.token.accountDate.dateType": "Date", + "bursarExports.token.accountDate.dateType.created": "Creation date", + "bursarExports.token.accountDate.dateType.updated": "Last updated date", + "bursarExports.token.accountDate.dateType.dueItem": "Item due date", + "bursarExports.token.accountDate.dateType.dueLoan": "Loan end date", + "bursarExports.token.accountDate.fallback.description": "If the chosen date is not available/applicable, the fallback value will be used instead.", + + "bursarExports.token.feeFineType.attribute": "Attribute", + "bursarExports.token.feeFineType.name": "Type name", + "bursarExports.token.feeFineType.id": "Type ID", + + "bursarExports.token.itemInfo.name": "Name", + "bursarExports.token.itemInfo.barcode": "Barcode", + "bursarExports.token.itemInfo.material": "Material type", + "bursarExports.token.itemInfo.instId": "Institution ID", + "bursarExports.token.itemInfo.campId": "Campus ID", + "bursarExports.token.itemInfo.libId": "Library ID", + "bursarExports.token.itemInfo.locId": "Location ID", + + "bursarExports.token.userInfo.folioId": "Folio ID", + "bursarExports.token.userInfo.extId": "External ID", + "bursarExports.token.userInfo.groupId": "Patron group ID", + "bursarExports.token.userInfo.barcode": "Barcode", + "bursarExports.token.userInfo.username": "Username", + "bursarExports.token.userInfo.firstname": "First name", + "bursarExports.token.userInfo.middlename": "Middle name", + "bursarExports.token.userInfo.lastname": "Last name", + + "bursarExports.token.constantConditional.value": "Then use:", + "bursarExports.token.constantConditional.description": "Conditions will be evaluated in order, with the first matched value being used. If no conditions are matched, the fallback value will be used.", + + "bursarExports.data.accordion.patron": "Patron data format", + "bursarExports.data.accordion.account": "Account data format", + + "bursarExports.preview.accordion": "Preview", + "bursarExports.preview.header": "Export preview", + "bursarExports.preview.wrap": "Wrap long lines", + "bursarExports.preview.description": "This preview is only a sample and does not represent real data, nor does it consider any specified criteria.", + "bursarExports.preview.enableInvisibleChar": "Display invisible characters (newlines, tabs, and spaces)", + + "bursarExports.transfer.accordion": "Transfer accounts to", + "bursarExports.transfer.description": "Conditions will be evaluated in order, with the first matched transfer account being used. If no conditions are matched, the account listed under \"otherwise\" will be used.", + "bursarExports.transfer.owner": "Fee/fine owner", + "bursarExports.transfer.account": "Transfer account", + "bursarExports.transfer.transferTo": "Transfer to", + "permission.bursar-exports.all": "Transfer exports: Modify configuration and start jobs", "permission.bursar-exports.manual": "Transfer exports: Start manual jobs", "permission.bursar-exports.view": "Transfer exports: View configuration" From 5922569987e28336d90bb8c17f2dca185ff918ed Mon Sep 17 00:00:00 2001 From: nhanaa Date: Fri, 16 Jun 2023 13:22:16 -0500 Subject: [PATCH 04/15] Replace quotes with smart quotes encoded --- translations/ui-plugin-bursar-export/en.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/translations/ui-plugin-bursar-export/en.json b/translations/ui-plugin-bursar-export/en.json index 022d3c64..2fc1dc3a 100644 --- a/translations/ui-plugin-bursar-export/en.json +++ b/translations/ui-plugin-bursar-export/en.json @@ -57,7 +57,7 @@ "bursarExports.aggregate.filter.operator.lessEqual": "Less than or equal to", "bursarExports.aggregate.filter.operator.greater": "Greater than but not equal to", "bursarExports.aggregate.filter.operator.greaterEqual": "Greater than or equal to", - "bursarExports.aggregate.filter.description": "This will be applied after accounts are evaluated per the \"Criteria\" specified above.", + "bursarExports.aggregate.filter.description": "This will be applied after accounts are evaluated per the \u201cCriteria\u201d specified above.", "bursarExports.header.accordion": "Header format", "bursarExports.footer.accordion": "Footer format", @@ -97,7 +97,7 @@ "bursarExports.token.currentDate.timezone": "Timezone", "bursarExports.token.accountAmount.enableDecimal": "Include the decimal point", - "bursarExports.token.accountAmount.enableDecimal.description": "If selected, amounts will be exported like \"12.50\" if left unselected, they will be exported like \"1250\".", + "bursarExports.token.accountAmount.enableDecimal.description": "If selected, amounts will be exported like \u201c12.50\u201d if left unselected, they will be exported like \u201c1250\u201d.", "bursarExports.token.accountDate.dateType": "Date", "bursarExports.token.accountDate.dateType.created": "Creation date", @@ -140,7 +140,7 @@ "bursarExports.preview.enableInvisibleChar": "Display invisible characters (newlines, tabs, and spaces)", "bursarExports.transfer.accordion": "Transfer accounts to", - "bursarExports.transfer.description": "Conditions will be evaluated in order, with the first matched transfer account being used. If no conditions are matched, the account listed under \"otherwise\" will be used.", + "bursarExports.transfer.description": "Conditions will be evaluated in order, with the first matched transfer account being used. If no conditions are matched, the account listed under \u201cotherwise\u201d will be used.", "bursarExports.transfer.owner": "Fee/fine owner", "bursarExports.transfer.account": "Transfer account", "bursarExports.transfer.transferTo": "Transfer to", From d177ac9bafde8de8a4868c80580c66e83b780f47 Mon Sep 17 00:00:00 2001 From: nhanaa Date: Fri, 16 Jun 2023 13:22:26 -0500 Subject: [PATCH 05/15] Keep none option at the top --- .../AggregateCriteriaCard.tsx | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/components/AggregateCriteria/AggregateCriteriaCard.tsx b/src/components/AggregateCriteria/AggregateCriteriaCard.tsx index f5cc6ab1..053ae472 100644 --- a/src/components/AggregateCriteria/AggregateCriteriaCard.tsx +++ b/src/components/AggregateCriteria/AggregateCriteriaCard.tsx @@ -1,5 +1,5 @@ import { Card, Col, Row, Select, TextField } from '@folio/stripes/components'; -import React from 'react'; +import React, { useMemo } from 'react'; import { CriteriaAggregateType } from '../../types/CriteriaTypes'; import { Field, useField } from 'react-final-form'; import OperatorSelect from '../Criteria/OperatorSelect'; @@ -15,6 +15,25 @@ export default function AggregateCriteriaCard() { const monetaryOnBlur = useMonetaryOnBlur('aggregateFilter.amountDollars'); const intl = useIntl(); + const criteriaOptions = useMemo( + () => + [ + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.numAccounts', + }), + value: CriteriaAggregateType.NUM_ROWS, + }, + { + label: intl.formatMessage({ + id: 'ui-plugin-bursar-export.bursarExports.aggregate.filter.totalAmount', + }), + value: CriteriaAggregateType.TOTAL_AMOUNT, + }, + ].sort((a, b) => a.label.localeCompare(b.label)), + [intl] + ); + return ( a.label.localeCompare(b.label))} + ...criteriaOptions, + ]} /> )} From 6a9937f3cee80e7b271e699766ae8de20caf7649 Mon Sep 17 00:00:00 2001 From: nhanaa Date: Fri, 16 Jun 2023 14:59:16 -0500 Subject: [PATCH 06/15] Remove debug accordions and TODO comments --- .../Criteria/CriteriaCardSelect.tsx | 1 - src/form/ConfigurationForm.tsx | 47 ------------------- 2 files changed, 48 deletions(-) diff --git a/src/components/Criteria/CriteriaCardSelect.tsx b/src/components/Criteria/CriteriaCardSelect.tsx index 2f9d5dc5..bfb3a944 100644 --- a/src/components/Criteria/CriteriaCardSelect.tsx +++ b/src/components/Criteria/CriteriaCardSelect.tsx @@ -55,7 +55,6 @@ export default function CriteriaCardSelect({ disabled: true, }, - // TODO: sort these alphabetically per i18n ...(patronOnly ? [ { diff --git a/src/form/ConfigurationForm.tsx b/src/form/ConfigurationForm.tsx index 8c737210..663e27e9 100644 --- a/src/form/ConfigurationForm.tsx +++ b/src/form/ConfigurationForm.tsx @@ -128,52 +128,6 @@ function ConfigurationForm({ > - - - - {({ values }) =>
{JSON.stringify(values, undefined, 2)}
} -
-
- - subscription={{ values: true }}> - {({ values }) => ( -
{JSON.stringify(formValuesToDto(values), undefined, 2)}
- )} - -
- -
{JSON.stringify(useCurrentConfig().data, undefined, 2)}
-
- -
{JSON.stringify(useInitialValues(), undefined, 2)}
-
- -
{JSON.stringify(usePatronGroups().data, undefined, 2)}
-
- -
{JSON.stringify(useServicePoints().data, undefined, 2)}
-
- -
{JSON.stringify(useFeeFineOwners().data, undefined, 2)}
-
- -
{JSON.stringify(useFeeFineTypes().data, undefined, 2)}
-
- -
{JSON.stringify(useTransferAccounts().data, undefined, 2)}
-
- -
{JSON.stringify(useInstitutions().data, undefined, 2)}
-
- -
{JSON.stringify(useCampuses().data, undefined, 2)}
-
- -
{JSON.stringify(useLibraries().data, undefined, 2)}
-
- -
{JSON.stringify(useLocations().data, undefined, 2)}
-
); @@ -181,5 +135,4 @@ function ConfigurationForm({ export default stripesFinalForm({ validateOnBlur: true, - // TODO: add validate, })(ConfigurationForm); From f3fd97a3cbc4293bf00dd2dacd001cce1fa5f3f4 Mon Sep 17 00:00:00 2001 From: nhanaa Date: Mon, 19 Jun 2023 10:38:50 -0500 Subject: [PATCH 07/15] Modify tests and translations to run properly --- .../Criteria/CriteriaCardSelect.test.tsx | 25 ++++++++++++------- .../Token/Data/FeeFineTypeToken.test.tsx | 25 +++++++++++-------- .../Token/Shared/DatePartPicker.test.tsx | 19 ++++++++------ src/form/sections/ExportPreview.test.tsx | 10 +++++--- translations/ui-plugin-bursar-export/en.json | 10 ++++---- 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/components/Criteria/CriteriaCardSelect.test.tsx b/src/components/Criteria/CriteriaCardSelect.test.tsx index 0711cf8b..03d0d4e9 100644 --- a/src/components/Criteria/CriteriaCardSelect.test.tsx +++ b/src/components/Criteria/CriteriaCardSelect.test.tsx @@ -2,13 +2,16 @@ import { render, screen } from '@testing-library/react'; import { Form } from 'react-final-form'; import CriteriaCardSelect from './CriteriaCardSelect'; import React from 'react'; +import withIntlConfiguration from '../../test/util/withIntlConfiguration'; describe('Criteria card selection box', () => { it('root has no criteria option', () => { render( -
- {() => } - + withIntlConfiguration( +
+ {() => } + + ) ); expect( @@ -18,9 +21,11 @@ describe('Criteria card selection box', () => { it('non patron-only has item/etc options', () => { render( -
- {() => } - + withIntlConfiguration( +
+ {() => } + + ) ); expect(screen.getByRole('option', { name: 'All of:' })).toBeInTheDocument(); @@ -34,9 +39,11 @@ describe('Criteria card selection box', () => { it('patron-only does not have item/etc options', () => { render( -
- {() => } - + withIntlConfiguration( +
+ {() => } + + ) ); expect(screen.getByRole('option', { name: 'All of:' })).toBeInTheDocument(); diff --git a/src/components/Token/Data/FeeFineTypeToken.test.tsx b/src/components/Token/Data/FeeFineTypeToken.test.tsx index 29f253c5..70b6d093 100644 --- a/src/components/Token/Data/FeeFineTypeToken.test.tsx +++ b/src/components/Token/Data/FeeFineTypeToken.test.tsx @@ -4,23 +4,26 @@ import React from 'react'; import { Form } from 'react-final-form'; import { DataTokenType } from '../../../types/TokenTypes'; import DataTokenCardBody from './DataTokenCardBody'; +import withIntlConfiguration from '../../../test/util/withIntlConfiguration'; describe('Fee/fine type token', () => { it('displays appropriate form', async () => { const submitter = jest.fn(); render( -
submitter(v)} - initialValues={{ test: { type: DataTokenType.FEE_FINE_TYPE } }} - > - {({ handleSubmit }) => ( - - - - - )} - + withIntlConfiguration( +
submitter(v)} + initialValues={{ test: { type: DataTokenType.FEE_FINE_TYPE } }} + > + {({ handleSubmit }) => ( + + + + + )} + + ) ); await userEvent.click(screen.getByRole('button', { name: 'Submit' })); diff --git a/src/components/Token/Shared/DatePartPicker.test.tsx b/src/components/Token/Shared/DatePartPicker.test.tsx index 610f8d87..be2e4e74 100644 --- a/src/components/Token/Shared/DatePartPicker.test.tsx +++ b/src/components/Token/Shared/DatePartPicker.test.tsx @@ -3,20 +3,23 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { Form } from 'react-final-form'; import DatePartPicker from './DatePartPicker'; +import withIntlConfiguration from '../../../test/util/withIntlConfiguration'; describe('Date part picker', () => { it('displays appropriate form', async () => { const submitter = jest.fn(); render( -
submitter(v)}> - {({ handleSubmit }) => ( - - - - - )} - + withIntlConfiguration( +
submitter(v)}> + {({ handleSubmit }) => ( + + + + + )} + + ) ); expect(screen.getByRole('combobox', { name: 'Format' })).toHaveDisplayValue( diff --git a/src/form/sections/ExportPreview.test.tsx b/src/form/sections/ExportPreview.test.tsx index bba99337..de0a0268 100644 --- a/src/form/sections/ExportPreview.test.tsx +++ b/src/form/sections/ExportPreview.test.tsx @@ -5,6 +5,7 @@ import { Form } from 'react-final-form'; import ExportPreview from './ExportPreview'; import { DataTokenType, HeaderFooterTokenType } from '../../types/TokenTypes'; import userEvent from '@testing-library/user-event'; +import withIntlConfiguration from '../../test/util/withIntlConfiguration'; jest.mock('@ngneat/falso', () => ({ randFloat: jest.fn(() => 12.34), @@ -14,11 +15,12 @@ jest.mock('@ngneat/falso', () => ({ describe('Export preview component', () => { it('wraps lines when selected', async () => { const { container } = render( -
- {() => } - + withIntlConfiguration( +
+ {() => } + + ) ); - // when undefined expect(container.querySelector('.wrap')).toBeVisible(); diff --git a/translations/ui-plugin-bursar-export/en.json b/translations/ui-plugin-bursar-export/en.json index 2fc1dc3a..e23537b2 100644 --- a/translations/ui-plugin-bursar-export/en.json +++ b/translations/ui-plugin-bursar-export/en.json @@ -22,9 +22,9 @@ "bursarExports.scheduling.weekdays": "Run on weekdays", "bursarExports.criteria.accordion": "Criteria", - "bursarExports.criteria.select.allOf": "All of", - "bursarExports.criteria.select.anyOf": "Any of", - "bursarExports.criteria.select.noneOf": "None of", + "bursarExports.criteria.select.allOf": "All of:", + "bursarExports.criteria.select.anyOf": "Any of:", + "bursarExports.criteria.select.noneOf": "None of:", "bursarExports.criteria.select.age": "Age", "bursarExports.criteria.select.amount": "Amount", "bursarExports.criteria.select.owner": "Fee/fine owner", @@ -32,7 +32,7 @@ "bursarExports.criteria.select.location": "Item location", "bursarExports.criteria.select.servicePoint": "Item service point", "bursarExports.criteria.select.patronGroup": "Patron group", - "bursarExports.criteria.select.none": "No criteria (alwyays run)", + "bursarExports.criteria.select.none": "No criteria (always run)", "bursarExports.criteria.age.value": "Older than (days)", "bursarExports.criteria.type.automatic": "Automatic", @@ -143,7 +143,7 @@ "bursarExports.transfer.description": "Conditions will be evaluated in order, with the first matched transfer account being used. If no conditions are matched, the account listed under \u201cotherwise\u201d will be used.", "bursarExports.transfer.owner": "Fee/fine owner", "bursarExports.transfer.account": "Transfer account", - "bursarExports.transfer.transferTo": "Transfer to", + "bursarExports.transfer.transferTo": "Transfer to:", "permission.bursar-exports.all": "Transfer exports: Modify configuration and start jobs", "permission.bursar-exports.manual": "Transfer exports: Start manual jobs", From 3073dbab0e11381845b7fb0a9fc33704474288fd Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Wed, 21 Jun 2023 14:50:10 -0500 Subject: [PATCH 08/15] Fix configuration form mocking/tests --- src/form/ConfigurationForm.test.tsx | 48 +++++++++++++++++++++++++++++ src/form/ConfigurationForm.tsx | 16 ++-------- 2 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 src/form/ConfigurationForm.test.tsx diff --git a/src/form/ConfigurationForm.test.tsx b/src/form/ConfigurationForm.test.tsx new file mode 100644 index 00000000..7f00f5a9 --- /dev/null +++ b/src/form/ConfigurationForm.test.tsx @@ -0,0 +1,48 @@ +import { render, screen } from '@testing-library/react'; +import arrayMutators from 'final-form-arrays'; +import React, { ComponentType } from 'react'; +import { Form, FormProps } from 'react-final-form'; +import withIntlConfiguration from '../test/util/withIntlConfiguration'; +import ConfigurationForm from './ConfigurationForm'; + +jest.mock('@folio/stripes/final-form', () => ({ + __esModule: true, + default: () => (Component: ComponentType) => (props: FormProps) => + ( +
+ {(formProps) => } + + ), +})); + +jest.mock('../api/queries/useFeeFineOwners', () => ({ + __esModule: true, + default: () => ({ data: [], isSuccess: true }), +})); + +jest.mock('../api/queries/useTransferAccounts', () => ({ + __esModule: true, + default: () => ({ data: [], isSuccess: true }), +})); + +describe('Configuration form', () => { + it('Render the configuration form', () => { + render( + withIntlConfiguration( + + ) + ); + + screen.debug(); + + expect(screen.getByText('Account data format')).toBeVisible(); + + // you should test the conditions for with/without aggregate + // (can `userEvent.click the checkbox, but you may need to open the accordion) + // you could also re-render and pass alternative initial values + }); +}); diff --git a/src/form/ConfigurationForm.tsx b/src/form/ConfigurationForm.tsx index 663e27e9..1d55f0a3 100644 --- a/src/form/ConfigurationForm.tsx +++ b/src/form/ConfigurationForm.tsx @@ -8,19 +8,8 @@ import { import stripesFinalForm from '@folio/stripes/final-form'; import { FormApi } from 'final-form'; import React, { FormEvent, MutableRefObject, useCallback } from 'react'; -import { FormRenderProps, FormSpy, useField } from 'react-final-form'; -import formValuesToDto from '../api/dto/to/formValuesToDto'; -import useCampuses from '../api/queries/useCampuses'; -import useCurrentConfig from '../api/queries/useCurrentConfig'; -import useFeeFineOwners from '../api/queries/useFeeFineOwners'; -import useFeeFineTypes from '../api/queries/useFeeFineTypes'; -import useInstitutions from '../api/queries/useInstitutions'; -import useLibraries from '../api/queries/useLibraries'; -import useLocations from '../api/queries/useLocations'; -import usePatronGroups from '../api/queries/usePatronGroups'; -import useServicePoints from '../api/queries/useServicePoints'; -import useTransferAccounts from '../api/queries/useTransferAccounts'; -import useInitialValues from '../hooks/useInitialValues'; +import { FormRenderProps, useField } from 'react-final-form'; +import { FormattedMessage } from 'react-intl'; import FormValues from '../types/FormValues'; import AggregateMenu from './sections/AggregateMenu'; import CriteriaMenu from './sections/CriteriaMenu'; @@ -29,7 +18,6 @@ import ExportPreview from './sections/ExportPreview'; import HeaderFooterMenu from './sections/HeaderFooterMenu'; import SchedulingMenu from './sections/SchedulingMenu'; import TransferInfoMenu from './sections/TransferInfoMenu'; -import { FormattedMessage } from 'react-intl'; export const FORM_ID = 'ui-plugin-bursar-export-form'; From 8126112e9daa11f7776860f6b5490a8ff75a6fe0 Mon Sep 17 00:00:00 2001 From: danetsao Date: Wed, 21 Jun 2023 16:49:58 -0500 Subject: [PATCH 09/15] Added test to render config form with different aggregate values --- src/form/ConfigurationForm.test.tsx | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/form/ConfigurationForm.test.tsx b/src/form/ConfigurationForm.test.tsx index 7f00f5a9..4092d786 100644 --- a/src/form/ConfigurationForm.test.tsx +++ b/src/form/ConfigurationForm.test.tsx @@ -41,8 +41,22 @@ describe('Configuration form', () => { expect(screen.getByText('Account data format')).toBeVisible(); - // you should test the conditions for with/without aggregate - // (can `userEvent.click the checkbox, but you may need to open the accordion) - // you could also re-render and pass alternative initial values }); + + it('Render the configuration form with aggregate initial true', () => { + render( + withIntlConfiguration( + + ) + ); + + screen.debug(); + + expect(screen.getByText('Patron data format')).toBeVisible(); + + }); }); From e28c492ee95c297009a5e1ae8a9e5998c6686cbe Mon Sep 17 00:00:00 2001 From: nhanaa Date: Thu, 22 Jun 2023 15:59:36 -0500 Subject: [PATCH 10/15] Add test for render BursarExportPlugin --- src/BursarExportPlugin.test.tsx | 64 +++++++++++++++++++++++++++++++++ src/BursarExportPlugin.tsx | 8 +++-- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/BursarExportPlugin.test.tsx diff --git a/src/BursarExportPlugin.test.tsx b/src/BursarExportPlugin.test.tsx new file mode 100644 index 00000000..a3e5bfbb --- /dev/null +++ b/src/BursarExportPlugin.test.tsx @@ -0,0 +1,64 @@ +import { render, screen } from '@testing-library/react'; +import React, { ComponentType } from 'react'; +import BursarExportPlugin from './BursarExportPlugin'; +import { useStripes } from '@folio/stripes/core'; +import withIntlConfiguration from './test/util/withIntlConfiguration'; +import useInitialValues from './hooks/useInitialValues'; +import { Form, FormProps } from 'react-final-form'; +import arrayMutators from 'final-form-arrays'; +import { FORM_ID } from './form/ConfigurationForm'; +import userEvent from '@testing-library/user-event'; +import formValuesToDto from './api/dto/to/formValuesToDto'; + +jest.mock('@folio/stripes/core', () => ({ + useStripes: jest.fn(), +})); +jest.mock('./api/mutators/useManualSchedulerMutation', () => jest.fn()); +jest.mock( + './api/mutators/useAutomaticSchedulerMutation', + () => () => jest.fn() +); +jest.mock('./hooks/useInitialValues', () => ({ + __esModule: true, + default: jest.fn(), +})); +jest.mock('@folio/stripes/final-form', () => ({ + __esModule: true, + default: () => (Component: ComponentType) => (props: FormProps) => + ( +
+ {(formProps) => } + + ), +})); +jest.mock('./api/queries/useFeeFineOwners', () => ({ + __esModule: true, + default: () => ({ data: [], isSuccess: true }), +})); + +jest.mock('./api/queries/useTransferAccounts', () => ({ + __esModule: true, + default: () => ({ data: [], isSuccess: true }), +})); + +describe('BursarExportPlugin', () => { + it('Renders the plugin with null initial values', () => { + (useInitialValues as jest.Mock).mockReturnValue(null); + + render(withIntlConfiguration()); + + expect(screen.getByText('Transfer configuration')).toBeVisible(); + expect(document.getElementById(FORM_ID)).toBeNull(); + }); + + it('Renders the plugin with initial values', async () => { + (useInitialValues as jest.Mock).mockReturnValue({}); + (useStripes as jest.Mock).mockReturnValue({ hasPerm: () => true }); + + render(withIntlConfiguration()); + + expect(screen.getByText('Transfer configuration')).toBeVisible(); + expect(document.getElementById(FORM_ID)).not.toBeNull(); + expect(screen.getByText('Account data format')).toBeVisible(); + }); +}); diff --git a/src/BursarExportPlugin.tsx b/src/BursarExportPlugin.tsx index ef836dab..cfbdc08d 100644 --- a/src/BursarExportPlugin.tsx +++ b/src/BursarExportPlugin.tsx @@ -46,10 +46,14 @@ export default function BursarExportPlugin() { defaultWidth="fill" footer={ Run manually} + renderStart={ + + } renderEnd={ } /> From 71a251628af7285e7230a1c789230330dbd62832 Mon Sep 17 00:00:00 2001 From: danetsao Date: Fri, 23 Jun 2023 16:16:00 -0500 Subject: [PATCH 11/15] Added aria-label to fix accessibility issues --- src/components/Criteria/CriteriaCardSelect.tsx | 8 +++++++- src/components/Token/Data/DataTypeSelect.tsx | 8 +++++++- .../Token/HeaderFooter/HeaderFooterTypeSelect.tsx | 8 +++++++- translations/ui-plugin-bursar-export/en.json | 5 +++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/components/Criteria/CriteriaCardSelect.tsx b/src/components/Criteria/CriteriaCardSelect.tsx index bfb3a944..87639cd2 100644 --- a/src/components/Criteria/CriteriaCardSelect.tsx +++ b/src/components/Criteria/CriteriaCardSelect.tsx @@ -124,7 +124,13 @@ export default function CriteriaCardSelect({ }, [root, patronOnly]); return ( - + {(fieldProps) => ( {...fieldProps} diff --git a/src/components/Token/Data/DataTypeSelect.tsx b/src/components/Token/Data/DataTypeSelect.tsx index d62abe86..fd9fa4b6 100644 --- a/src/components/Token/Data/DataTypeSelect.tsx +++ b/src/components/Token/Data/DataTypeSelect.tsx @@ -146,7 +146,13 @@ export default function DataTypeSelect({ name }: { name: string }) { ); return ( - + {(fieldProps) => ( {...fieldProps} diff --git a/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx b/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx index 406089fa..d5eb9ac3 100644 --- a/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx +++ b/src/components/Token/HeaderFooter/HeaderFooterTypeSelect.tsx @@ -82,7 +82,13 @@ export default function HeaderFooterTypeSelect({ name }: { name: string }) { }, [intl]); return ( - + {(fieldProps) => ( {...fieldProps} diff --git a/translations/ui-plugin-bursar-export/en.json b/translations/ui-plugin-bursar-export/en.json index e23537b2..62e812b8 100644 --- a/translations/ui-plugin-bursar-export/en.json +++ b/translations/ui-plugin-bursar-export/en.json @@ -33,6 +33,7 @@ "bursarExports.criteria.select.servicePoint": "Item service point", "bursarExports.criteria.select.patronGroup": "Patron group", "bursarExports.criteria.select.none": "No criteria (always run)", + "bursarExports.criteria.select.label": "Criteria", "bursarExports.criteria.age.value": "Older than (days)", "bursarExports.criteria.type.automatic": "Automatic", @@ -81,6 +82,10 @@ "bursarExports.token.fallback.description": "If the chosen date is not available/applicable, the fallback value will be used instead.", "bursarExports.token.value": "Value", + "bursarExports.token.headerFooter.typeSelect": "Header/footer type select", + + "bursarExports.token.dataType.typeSelect": "Data type select", + "bursarExports.token.whitespace.numSpaces": "Number of spaces", "bursarExports.token.currentDate.format": "Format", From a08d4230e94e1506d7906f9de2f66f2916711492 Mon Sep 17 00:00:00 2001 From: nhanaa Date: Mon, 26 Jun 2023 13:16:56 -0500 Subject: [PATCH 12/15] Modify tests to add more coverage --- src/BursarExportPlugin.test.tsx | 55 +++++++++++++++++++++++++---- src/form/ConfigurationForm.test.tsx | 8 ++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/BursarExportPlugin.test.tsx b/src/BursarExportPlugin.test.tsx index a3e5bfbb..e909204a 100644 --- a/src/BursarExportPlugin.test.tsx +++ b/src/BursarExportPlugin.test.tsx @@ -9,11 +9,13 @@ import arrayMutators from 'final-form-arrays'; import { FORM_ID } from './form/ConfigurationForm'; import userEvent from '@testing-library/user-event'; import formValuesToDto from './api/dto/to/formValuesToDto'; +import { OptionType } from '@folio/stripes-types/components/lib/Select/Select'; +import schedulingToDto from './api/dto/to/schedulingToDto'; jest.mock('@folio/stripes/core', () => ({ useStripes: jest.fn(), })); -jest.mock('./api/mutators/useManualSchedulerMutation', () => jest.fn()); +jest.mock('./api/mutators/useManualSchedulerMutation', () => () => jest.fn()); jest.mock( './api/mutators/useAutomaticSchedulerMutation', () => () => jest.fn() @@ -31,18 +33,32 @@ jest.mock('@folio/stripes/final-form', () => ({ ), })); + +const feeFineOwner = { + owner: 'Test owner', + id: 'test_owner_id', +}; +const transferAccount = { + accountName: 'Test account', + ownerId: 'test_owner_id', + id: 'test_account_id', + desc: 'Test description', +}; + jest.mock('./api/queries/useFeeFineOwners', () => ({ __esModule: true, - default: () => ({ data: [], isSuccess: true }), + default: () => ({ data: [feeFineOwner], isSuccess: true }), })); jest.mock('./api/queries/useTransferAccounts', () => ({ __esModule: true, - default: () => ({ data: [], isSuccess: true }), + default: () => ({ data: [transferAccount], isSuccess: true }), })); +jest.mock('./api/dto/to/formValuesToDto', () => jest.fn()); +jest.mock('./api/dto/to/schedulingToDto', () => jest.fn()); describe('BursarExportPlugin', () => { - it('Renders the plugin with null initial values', () => { + it('renders the plugin with null initial values', () => { (useInitialValues as jest.Mock).mockReturnValue(null); render(withIntlConfiguration()); @@ -51,8 +67,8 @@ describe('BursarExportPlugin', () => { expect(document.getElementById(FORM_ID)).toBeNull(); }); - it('Renders the plugin with initial values', async () => { - (useInitialValues as jest.Mock).mockReturnValue({}); + it('fills out the form and then saves and runs the plugin', async () => { + (useInitialValues as jest.Mock).mockReturnValue({ aggregate: false }); (useStripes as jest.Mock).mockReturnValue({ hasPerm: () => true }); render(withIntlConfiguration()); @@ -60,5 +76,32 @@ describe('BursarExportPlugin', () => { expect(screen.getByText('Transfer configuration')).toBeVisible(); expect(document.getElementById(FORM_ID)).not.toBeNull(); expect(screen.getByText('Account data format')).toBeVisible(); + expect(screen.getByText('Save')).toBeVisible(); + + expect(screen.queryByText('Transfer to:')).not.toBeNull(); + + const frequencyDropdown = document.querySelector( + '[name = "scheduling.frequency"]' + ) as HTMLSelectElement; + await userEvent.selectOptions(frequencyDropdown, 'NONE'); + + const ownerDropdown = document.querySelector( + '[name = "transferInfo.else.owner"]' + ) as HTMLSelectElement; + await userEvent.selectOptions(ownerDropdown, 'test_owner_id'); + + const accountDropdown = document.querySelector( + '[name = "transferInfo.else.account"]' + ) as HTMLSelectElement; + await userEvent.selectOptions(accountDropdown, 'test_account_id'); + + await userEvent.click(screen.getByText('Save')); + + expect(formValuesToDto).toHaveBeenCalled(); + expect(schedulingToDto).toHaveBeenCalled(); + + await userEvent.click(screen.getByText('Run manually')); + + expect(formValuesToDto).toHaveBeenCalled(); }); }); diff --git a/src/form/ConfigurationForm.test.tsx b/src/form/ConfigurationForm.test.tsx index 4092d786..3cf9483f 100644 --- a/src/form/ConfigurationForm.test.tsx +++ b/src/form/ConfigurationForm.test.tsx @@ -26,7 +26,7 @@ jest.mock('../api/queries/useTransferAccounts', () => ({ })); describe('Configuration form', () => { - it('Render the configuration form', () => { + it('renders the configuration form', () => { render( withIntlConfiguration( { screen.debug(); expect(screen.getByText('Account data format')).toBeVisible(); - }); - it('Render the configuration form with aggregate initial true', () => { + it('renders the configuration form with aggregate initial true', () => { render( withIntlConfiguration( { screen.debug(); expect(screen.getByText('Patron data format')).toBeVisible(); - - }); + }); }); From 7acf86e91b1c1e57ae00ea672d64231a201cc60c Mon Sep 17 00:00:00 2001 From: nhanaa Date: Mon, 26 Jun 2023 13:57:18 -0500 Subject: [PATCH 13/15] Refactor code to fix duplications --- src/components/Token/Data/ItemInfoToken.tsx | 80 +++++++++--------- src/components/Token/Data/UserInfoToken.tsx | 89 +++++++++------------ 2 files changed, 75 insertions(+), 94 deletions(-) diff --git a/src/components/Token/Data/ItemInfoToken.tsx b/src/components/Token/Data/ItemInfoToken.tsx index 8fa39e9d..826c72c5 100644 --- a/src/components/Token/Data/ItemInfoToken.tsx +++ b/src/components/Token/Data/ItemInfoToken.tsx @@ -5,51 +5,43 @@ import { useIntl } from 'react-intl'; export default function ItemInfoToken({ prefix }: { prefix: string }) { const intl = useIntl(); + const attributeOptions = [ + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.name', + value: 'NAME', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.barcode', + value: 'BARCODE', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.material', + value: 'MATERIAL_TYPE', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.instId', + value: 'INSTITUTION_ID', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.campId', + value: 'CAMPUS_ID', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.libId', + value: 'LIBRARY_ID', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.locId', + value: 'LOCATION_ID', + }, + ]; const options = useMemo(() => { - const selectOptions = [ - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.name', - }), - value: 'NAME' as ItemAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.barcode', - }), - value: 'BARCODE' as ItemAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.material', - }), - value: 'MATERIAL_TYPE' as ItemAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.instId', - }), - value: 'INSTITUTION_ID' as ItemAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.campId', - }), - value: 'CAMPUS_ID' as ItemAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.libId', - }), - value: 'LIBRARY_ID' as ItemAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.itemInfo.locId', - }), - value: 'LOCATION_ID' as ItemAttribute, - }, - ].sort((a, b) => a.label.localeCompare(b.label)); + const selectOptions = attributeOptions + .map((option) => ({ + label: intl.formatMessage({ id: option.labelId }), + value: option.value as ItemAttribute, + })) + .sort((a, b) => a.label.localeCompare(b.label)); return selectOptions; }, [intl]); diff --git a/src/components/Token/Data/UserInfoToken.tsx b/src/components/Token/Data/UserInfoToken.tsx index 1b0f682b..4a7f7ca4 100644 --- a/src/components/Token/Data/UserInfoToken.tsx +++ b/src/components/Token/Data/UserInfoToken.tsx @@ -6,57 +6,46 @@ import { UserAttribute } from '../../../types/TokenTypes'; export default function UserInfoToken({ prefix }: { prefix: string }) { const intl = useIntl(); + const attributeOptions = [ + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.folioId', + value: 'FOLIO_ID', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.extId', + value: 'EXTERNAL_SYSTEM_ID', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.groupId', + value: 'PATRON_GROUP_ID', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.barcode', + value: 'BARCODE', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.username', + value: 'USERNAME', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.firstname', + value: 'FIRST_NAME', + }, + { + labelId: + 'ui-plugin-bursar-export.bursarExports.token.userInfo.middlename', + value: 'MIDDLE_NAME', + }, + { + labelId: 'ui-plugin-bursar-export.bursarExports.token.userInfo.lastname', + value: 'LAST_NAME', + }, + ]; const options = useMemo(() => { - const selectOptions = [ - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.folioId', - }), - value: 'FOLIO_ID' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.extId', - }), - value: 'EXTERNAL_SYSTEM_ID' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.groupId', - }), - value: 'PATRON_GROUP_ID' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.barcode', - }), - value: 'BARCODE' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.username', - }), - value: 'USERNAME' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.firstname', - }), - value: 'FIRST_NAME' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.middlename', - }), - value: 'MIDDLE_NAME' as UserAttribute, - }, - { - label: intl.formatMessage({ - id: 'ui-plugin-bursar-export.bursarExports.token.userInfo.lastname', - }), - value: 'LAST_NAME' as UserAttribute, - }, - ]; + const selectOptions = attributeOptions.map((option) => ({ + label: intl.formatMessage({ id: option.labelId }), + value: option.value as UserAttribute, + })); return selectOptions; }, [intl]); From f1c9ce7ed621ad1d72364cc4782070c8a7bbcca1 Mon Sep 17 00:00:00 2001 From: nhanaa Date: Mon, 26 Jun 2023 14:17:07 -0500 Subject: [PATCH 14/15] Fix some code smells --- src/components/Token/Data/ItemInfoToken.tsx | 19 ++++++++++--------- src/components/Token/Data/UserInfoToken.tsx | 15 ++++++++------- .../Token/Shared/TimezonePicker.tsx | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/Token/Data/ItemInfoToken.tsx b/src/components/Token/Data/ItemInfoToken.tsx index 826c72c5..1c50bf59 100644 --- a/src/components/Token/Data/ItemInfoToken.tsx +++ b/src/components/Token/Data/ItemInfoToken.tsx @@ -35,15 +35,16 @@ export default function ItemInfoToken({ prefix }: { prefix: string }) { value: 'LOCATION_ID', }, ]; - const options = useMemo(() => { - const selectOptions = attributeOptions - .map((option) => ({ - label: intl.formatMessage({ id: option.labelId }), - value: option.value as ItemAttribute, - })) - .sort((a, b) => a.label.localeCompare(b.label)); - return selectOptions; - }, [intl]); + const options = useMemo( + () => + attributeOptions + .map((option) => ({ + label: intl.formatMessage({ id: option.labelId }), + value: option.value as ItemAttribute, + })) + .sort((a, b) => a.label.localeCompare(b.label)), + [intl] + ); return ( diff --git a/src/components/Token/Data/UserInfoToken.tsx b/src/components/Token/Data/UserInfoToken.tsx index 4a7f7ca4..bb9cd613 100644 --- a/src/components/Token/Data/UserInfoToken.tsx +++ b/src/components/Token/Data/UserInfoToken.tsx @@ -41,13 +41,14 @@ export default function UserInfoToken({ prefix }: { prefix: string }) { value: 'LAST_NAME', }, ]; - const options = useMemo(() => { - const selectOptions = attributeOptions.map((option) => ({ - label: intl.formatMessage({ id: option.labelId }), - value: option.value as UserAttribute, - })); - return selectOptions; - }, [intl]); + const options = useMemo( + () => + attributeOptions.map((option) => ({ + label: intl.formatMessage({ id: option.labelId }), + value: option.value as UserAttribute, + })), + [intl] + ); return ( diff --git a/src/components/Token/Shared/TimezonePicker.tsx b/src/components/Token/Shared/TimezonePicker.tsx index b13222d1..239fa0e2 100644 --- a/src/components/Token/Shared/TimezonePicker.tsx +++ b/src/components/Token/Shared/TimezonePicker.tsx @@ -1,6 +1,6 @@ import { Select } from '@folio/stripes/components'; import React, { useMemo } from 'react'; -import { Field, Form } from 'react-final-form'; +import { Field } from 'react-final-form'; import { FormattedMessage, useIntl } from 'react-intl'; import timeZones from '../../../utils/timezones'; From 1d7db1ff335f28c683703470072870eb7abb74a5 Mon Sep 17 00:00:00 2001 From: nhanaa Date: Tue, 27 Jun 2023 13:26:49 -0500 Subject: [PATCH 15/15] Fix code smells --- src/BursarExportPlugin.test.tsx | 1 - src/components/Criteria/CriteriaFeeFineOwner.tsx | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/BursarExportPlugin.test.tsx b/src/BursarExportPlugin.test.tsx index e909204a..ef3fcfc7 100644 --- a/src/BursarExportPlugin.test.tsx +++ b/src/BursarExportPlugin.test.tsx @@ -9,7 +9,6 @@ import arrayMutators from 'final-form-arrays'; import { FORM_ID } from './form/ConfigurationForm'; import userEvent from '@testing-library/user-event'; import formValuesToDto from './api/dto/to/formValuesToDto'; -import { OptionType } from '@folio/stripes-types/components/lib/Select/Select'; import schedulingToDto from './api/dto/to/schedulingToDto'; jest.mock('@folio/stripes/core', () => ({ diff --git a/src/components/Criteria/CriteriaFeeFineOwner.tsx b/src/components/Criteria/CriteriaFeeFineOwner.tsx index a3434434..8f3d38c9 100644 --- a/src/components/Criteria/CriteriaFeeFineOwner.tsx +++ b/src/components/Criteria/CriteriaFeeFineOwner.tsx @@ -12,10 +12,12 @@ export default function CriteriaFeeFineOwner({ prefix }: { prefix: string }) { return []; } - return feeFineOwners.data.map((owner) => ({ - label: owner.owner, - value: owner.id, - })); + return feeFineOwners.data + .map((owner) => ({ + label: owner.owner, + value: owner.id, + })) + .sort((a, b) => a.label.localeCompare(b.label)); }, [feeFineOwners]); return ( @@ -33,9 +35,7 @@ export default function CriteriaFeeFineOwner({ prefix }: { prefix: string }) { } dataOptions={[ { label: '', value: '', disabled: true }, - ...ownersSelectOptions.sort((a, b) => - a.label.localeCompare(b.label) - ), + ...ownersSelectOptions, ]} /> )}