Direct Debit Processing Calendar

Single page web application developed for Cancer Research UK to calculate Direct Debit processing days for a selected year by accounting for weekends, bank holidays and other non-work days. Uses the UK Government's Bank Holidays API to fetch data dynamically.

Stack

  • HTML/CSS
  • JavaScript
  • React
  • React-BootStrap
  • Styled Components
  • Vitest / Jest

Code & Docs

Direct Debits header

The purpose

This is v2 of a browser app that determines Direct Debit processing days for a selected year.

Companies using the Direct Debit scheme rely on a processing calendar to schedule these processes accurately, accounting for working days, bank holidays, weekends, and office closures.

Previously, determining these dates was a manual, complex, and error-prone task. This app automates the process, reducing potential errors and risks such as missed or delayed submissions, payment reconciliation issues, and reputational damage from failing to meet terms of the Direct Debit guarantee.

The app generates results in a format tailored for the Apps Support team, allowing one-click copying to the clipboard and easy data loading.

Direct Debits results

Features

  • Calculates and displays non-processing days (bank holidays and weekends) for a given year.
  • Allows users to manually add or delete company-specific non-processing days (e.g. office closures), with the results table updating dynamically.
  • Displays results in a tabbed UI, with a clean and organized layout.
  • Includes a 'Copy to clipboard' button for easy export of the results table.
  • Provides visual feedback for user interactions with 'toast' notifications that stack and auto-clear.
  • Features a comprehensive test suite to ensure high reliability and near 100% unit test coverage.

Web Stack & Tech

For the app's core functionality, I used JavaScript, focusing on the JS Date object for accurate date calculations. The app dynamically retrieves dates from the UK Government's Bank Holidays API, accommodating changes like extra bank holidays.

Originally, the app was built with vanilla JS and a basic Bootstrap interface, prioritizing functionality over aesthetics. It has since undergone a significant refactor: the UI now uses React components, including CRUK's React component library built with styled-components. React state management replaced traditional JS DOM manipulation, enabling dynamic updates without refreshing the browser, greatly enhancing the user experience.

To integrate the original UI elements, I employed React-BootStrap for familiar Bootstrap components. The unit tests were updated from Mocha/Chai to Vitest, benefiting from Vite integration and Jest API compatibility. This setup offers clear assertions, integrated mocking, and code coverage visualization.

Deployment is handled via Netlify, streamlining the CI/CD process.

You can find the original repo here and see below for a visual comparison:

DD app version comparison

Challenges

The app generates results by comparing potential processing dates against non-working days from the API (weekends and bank holidays) and user-inputted company-specific holidays. If there's a clash, the app needs to shift the date and recalculate until no conflicts remain, which involved some complex nested loops.

Dates in each column are interdependent, and sometimes affected byedge cases such as non-processing dates from previous or subsequent years, which the app's logic also accounts for.

Upgrading to a React application involved refactoring UI elements for modularity and dynamic rendering, and restructuring functionality to work with React's virtual DOM. This was a challenge but at the same time, a great exercise in design thinking - analysing the app's process flow, simplifying and breaking down functions and UI elements further where necessary, improving clarity and reusability.

Refactoring was aided by existing unit tests, facilitating atest-driven approach. React's modular structure helped me to further isolate functions to components themselves, rather than as side effects arising from other functions, allowing for a clearer separation of concerns. The React Context API provided clearer state management.

Testing the 'copy to clipboard' function in Vitest involved some extra complexity without certain DOM elements in a testing environment. I nonetheless managed this by mocking:

  • The navigator object using 'vi' in Vitest;
  • The document object using JSDOM;

To ensure consistent output, I standardized the data structurereturned by functions. This made the app's output more predictable and supported debugging through structured tests.

For further details on app-specific challenges, such as handling the JavaScript Date object, see my original repo here.

Challenges dd-v2-company,dd-v2-vitest-dashboard,dd-v2-vitest-coverageChallenges dd-v2-company,dd-v2-vitest-dashboard,dd-v2-vitest-coverageChallenges dd-v2-company,dd-v2-vitest-dashboard,dd-v2-vitest-coverage

Lessons

While the app gave me a lot of experience working with the Date object in JavaScript, there are JS date libraries which could simplify the process of converting and working with dates, thereby speeding up production. For example, date-fns or Moment.js.

While my eventual unit test coverage was close to 100%, I learned first-hand that this is not the only metric for effective tests - there is always room to improve their quality and handling of edge cases. An app can also benefit from integration and end-to-end testing where possible. In this case, I mocked integration testing using data to ensure the app's output would be correct. I am looking to further explore the possibilities of integration and end-to-end testing using faking/stubbing tools such as Sinon.js, and E2E testing suites such as Cypress, while also testing React components with React Testing Library.

Other Projects

Schillinger Rhythm Generator

Sliding Puzzle