npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@embedded-banking-fundr/invoice-finance

v2.2.6

Published

## Overview

Downloads

67

Readme

Rabobank Invoice Finance

Overview

The Rabobank Invoice Finance web component is a specialized tool tailored for small and medium-sized enterprises (SMEs) seeking financial solutions. By leveraging outstanding invoices, businesses can access loans of up to 100k seamlessly. This widget empowers partners by simplifying the integration process, allowing them to effortlessly incorporate Rabobank's innovative invoice financing service into their own product flows. With a focus on efficiency and ease of use, this component facilitates access to essential financial resources, enabling SMEs to thrive in today's dynamic business landscape.

Table of Contents

Installation

To incorporate the Rabobank Invoice Finance into your project, install it using npm or yarn:

NPM

npm i @embedded-banking-fundr/invoice-finance@latest

Yarn

yarn add @embedded-banking-fundr/invoice-finance@latest

Change log

All notable changes to this project are documented in the CHANGELOG.md file.

Properties

Configure the widget using the properties below and pass them as component properties. The web component essentially functions as an HTML element, allowing you to include HTML properties in the widget as well.

The identifier and partner properties are crucial for initializing the widget. Without these properties, the widget cannot function properly. They are utilized within the initWidget function to ensure the widget operates correctly.

The input elements will be automatically populated with the provided properties. For instance, when entering a KvK number (Chamber of Commerce number), the manual company verification screen will be automated, eliminating the requirement for user intervention. The system performs automatic checks, and if a company is found to be ineligible, an error modal will be presented accordingly. This process is replicated for populating invoice data. Once all invoice data is validated, the invoice will be seamlessly added without manual intervention. All invoice fields are mandatory for this process to be executed, except for the "debtorKvk" property.

| initWidget | Description | Type | Example | Required | | ----------------------------- | ---------------------------------- | ------------- | ------------------------------------ | --------- | | identifier | Identifier for the partner | string | "unique_string" | x | | partner | Identifier for the partner | string | "unique_string" | x |

| Webcomponent | Description | Type | Example | Required | | ----------------------------- | ---------------------------------- | ------------- | ------------------------------------ | --------- | | mode | Mode of the widget | string | "sandbox" | | | contact-details | Contact person's details | json | | | | contact-details.name | Contact person's name | string | "John" | | | contact-details.surname | Contact person's surname | string | "Doe" | | | contact-details.phone | Contact person's phone number | string | "0612345678" | | | contact-details.email | Contact person's email address | string | "[email protected]" | | | is-modal | Shows a button to close the widget | boolean | true | | | kvk-number | KVK number for the company | string | "12345678" | | | invoices | List of invoices | string | | | | invoices[].invoiceNumber | ID of the invoice | string | "INV1234567" | - | | invoices[].amount | Invoice amount | string | "1000" | - | | invoices[].issueDate | Date the invoice is issued | string | "2024-01-01" | - | | invoices[].deadlineDate | Date for invoice payment | string | "2024-01-31" | - | | invoices[].debtorName | Name of the debtor | string | "John Doe" | - | | invoices[].debtorKvk | KvK number of the debtor | string | "12345678" | | | invoices[].filename | Name of the invoice file | string | "invoice.pdf" | - | | invoices[].invoiceUrl | Invoice as a base64 data url | data uri | "data:application/pdf;base64,JV.." | - |

Please ensure that the invoice URL adheres to the data URI format. The absence of URI data will hinder the automation of the invoice process. Mandatory properties marked with '-' are essential for pre-filling and generating the invoice.


Mode: sandbox

During development, you can configure the mode as either sandbox or mock. When set to sandbox, the API URL will be automatically adjusted to utilize the testing environment for the backend. Although the endpoints are real, the majority of the data is mocked in the backend. To utilize the sandbox mode, the identifier is required. It's important to note that this identifier differs from the production identifier.

Mode: mock

When the mode is configured as mock, all endpoints will be mocked, removing the necessity for a backend environment. This functionality should only be used in development environments. It simplifies development by eliminating the reliance on an external backend environment. To activate the mock mode, you need to initialize MSW first by following these steps:

React

npx msw init ./public

Angular

npx msw init ./src

In the angular.json file, you need to include src/mockServiceWorker.js within the assets array of the project.

Vue

npx msw init ./

NextJs

npx msw init ./public

Mode: production

This mode is intended for actual production usage and generates genuine requests for clients. It should only be utilized when deploying to a production environment. Access to production mode requires a unique identifier provided to the partner.

IsModal

The isModal property is a boolean that controls the display of a special button at the top of the widget. When isModal is set to true, a button appears, offering users an additional level of interaction. This button is designed to emit the exit event, as detailed in the Available Events and Data section. The exit event can be leveraged to close the widget or trigger other closing-related actions, providing a convenient mechanism for managing the widget's lifecycle.

Usage in Different Frameworks

Web components are universally compatible with every framework. To integrate them, simply follow the steps outlined for your preferred framework. Execute the initWidget function to configure the partner identification. This step is crucial, as the widget will not operate properly without these specifics.

React

import React from 'react';
import { type ContactDetails, InvoiceDetails, initWidget } from '@embedded-banking-fundr/invoice-finance';

import '@embedded-banking-fundr/invoice-finance/style.css';

function Widget() {
  const contactDetails: ContactDetails = {
    name: 'John',
    surname: 'Doe',
    phone: '0612345678',
    email: '[email protected]',
  };

  const invoiceDetails: InvoiceDetails = {
    invoiceNumber: 'INV123456',
    amount: 1000,
    issueDate: '2024-01-01',
    deadlineDate: '2024-01-31',
    debtorName: 'John Doe',
    filename: 'INV123456.pdf',
    invoiceUrl, // invoice file converted to base64
  };

  const contact = JSON.stringify(contactDetails);
  const invoices = JSON.stringify([invoiceDetails]);

  initWidget({
    identifier: 'unique_key',
    partner: 'partner_id',
  });

  return (
    <rabobank-ff
      kvk-number="12345678"
      mode="sandbox"
      contact-details={contact}
      invoices={invoices}
    />
  );
}

export default Widget;

Angular

Update your schemas in either a module or component to include "CUSTOM_ELEMENTS_SCHEMA":

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
...

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule
    ],
    providers: [],
    bootstrap: [
      AppComponent,
      ],
    schemas:[
      CUSTOM_ELEMENTS_SCHEMA,
    ]
})
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';
import { initWidget } from '@embedded-banking-fundr/invoice-finance';

import '@embedded-banking-fundr/invoice-finance/style.css';

@Component({
  selector: 'app-rabobank-ff-container',
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <rabobank-ff
      [kvkNumber]=kvkNumber
      [mode]=mode
      [contactDetails]=contact
      [invoices]=invoices
    />`,
})
export class InvFinWrapperComponent {
  constructor() {
    initWidget({
      identifier: 'unique_key',
      partner: 'partner_id',
    });
  };

  kvkNumber = '12345678';
  mode = 'mock';

  contact = {
    name: 'John',
    surname: 'Doe',
    email: '[email protected]',
    phone: '0612345678',
  };

  invoiceDetails = {
    invoiceNumber: 'INV123456',
    amount: 1000,
    issueDate: '2024-01-01',
    deadlineDate: '2024-01-31',
    debtorName: 'John Doe',
    filename: 'INV123456.pdf',
    invoiceUrl, // invoice file converted to base64
  };

  invoices = [invoiceDetails];
}

Please be aware that when utilizing variables for the web component, the properties are in camel case. However, when directly hardcoding values to the web component, they must be in kebab case, otherwise, it will not function correctly.

Vue

<script setup lang="ts">
import {
  type ContactDetails,
  type InvoiceDetails,
  initWidget,
} from '@embedded-banking-fundr/invoice-finance';

import '@embedded-banking-fundr/invoice-finance/style.css';

const contactDetails: ContactDetails = {
  name: 'John',
  surname: 'Doe',
  phone: '0612345678',
  email: '[email protected]',
};

const invoiceDetails: InvoiceDetails = {
  invoiceNumber: 'INV123456',
  amount: 1000,
  issueDate: '2024-01-01',
  deadlineDate: '2024-01-31',
  debtorName: 'John Doe',
  filename: 'INV123456.pdf',
  invoiceUrl, // invoice file converted to base64
};

const contact = JSON.stringify(contactDetails);
const invoices = JSON.stringify([invoiceDetails]);

initWidget({
  identifier: 'unique_key',
  partner: 'partner_id',
});
</script>

<template>  
  <rabobank-ff
    kvk-number='12345678'
    mode='mock'
    :contact-details="contact"
    :invoices="invoices"
  />
</template>

NextJs

'use client';

import { useEffect, useState } from 'react';

import '@embedded-banking-fundr/invoice-finance/style.css';

export default function Home() {
  const [isFinished, setIsFinished] = useState(false);

  const contactDetails = {
    name: 'John',
    surname: 'Doe',
    phone: '0612345678',
    email: '[email protected]',
  };

  const invoiceDetails = {
    invoiceNumber: 'INV123456',
    amount: 1000,
    issueDate: '2024-01-01',
    deadlineDate: '2024-01-31',
    debtorName: 'John Doe',
    filename: 'INV123456.pdf',
    invoiceUrl, // invoice file converted to base64
  };

  const contact = JSON.stringify(contactDetails);
  const invoices = JSON.stringify([invoiceDetails]);

  useEffect(() => {
    const handleImport = async () => {
      const { initWidget } = await import('@embedded-banking-fundr/invoice-finance');

      initWidget({
        identifier: 'unique_key',
        partner: 'partner_id',
      });

      setIsFinished(true);
    }

    handleImport();
  }, []);

  return isFinished && (
    <rabobank-ff
      kvk-number='12345678'
      mode="mock"
      contact-details={contact}
      invoices={invoices}
    />
  );
}

Styling

Customize the component's visual attributes using CSS variables. The foreground variable determines the text color, adapting it based on the background color.

<style>
  rabobank-ff {
    --rabo-font-family: 'Manrope';
    --rabo-foreground: 220 2% 26%;

    --rabo-off-black: 0 0% 20%;
    --rabo-white: 0 0% 100%;

    --rabo-font-lineheight-xs: 1.00rem;
    --rabo-font-lineheight-sm: 1.50rem;
    --rabo-font-lineheight-md: 1.25rem;
    --rabo-font-lineheight-lg: 1.50rem;
    --rabo-font-lineheight-xl: 2.50rem;

    --rabo-font-size-xs: 0.750rem;
    --rabo-font-size-sm: 0.900rem;
    --rabo-font-size-md: 1.000rem;
    --rabo-font-size-lg: 1.250rem;
    --rabo-font-size-xl: 2.000rem;

    --rabo-primary: 202 90% 58%;
    --rabo-primary-foreground: var(--rabo-white);

    --rabo-secondary: 202 79% 26%;
    --rabo-secondary-foreground: var(--rabo-white);

    --rabo-input-disabled: 210 40% 98%;
    --rabo-input-disabled-foreground: 215 11% 65%;

    --rabo-button-disabled: 213 27% 84%;
    --rabo-button-disabled-foreground: var(--rabo-white);

    --rabo-destructive: 0 60% 52%;
    --rabo-destructive-foreground: var(--rabo-white);

    --rabo-success: 160 100% 40%;
    --rabo-success-foreground: var(--rabo-white);

    --rabo-warning: 49 93% 67%;
    --rabo-warning-foreground: var(--rabo-foreground);

    --rabo-border: 220 2% 74%;
    --rabo-radius: 0.25rem;

    --rabo-min-height: 35.5rem; /* 568px */
    --rabo-max-height: 52.0rem; /* 832px */

    --rabo-min-width: 23rem; /* 368px */
    --rabo-max-width: 40rem; /* 640px */

    --rabo-app-background: var(--rabo-white);
    --rabo-navigation-bar: var(--rabo-white);

    --rabo-modal-overlay: var(--rabo-off-black);
    --rabo-shadow: 0 0% 0%;

    --rabo-app-border-radius: 0.25rem;

    --rabo-input-border: 0 0% 80%;
    --rabo-input-placeholder: 210 2% 62%;
  }
</style>

Dimensions

For optimal performance, the web component is most effective when integrated into a page where the parent element(s) either possess a fixed height or have a height set to 100%. If this prerequisite isn't fulfilled, it's recommended to introduce a wrapper or apply inline styling to ensure the web component maintains a fixed height. In cases where a fixed height is not needed, the application will utilize its minimum and maximum heights to display the content. The minimum width is set at 368px, with a default minimum height of 568px and a default maximum height of 832px. These values are customizable, as indicated in the styling section above.

Event Handling

The widget emits various events that can be captured by subscribing to a listener, enabling notifications for different interactions and states. Below is a list of these events along with their descriptions:

Subscribing to Events

To respond to these events, you can subscribe to the listener from anywhere within your application using the subscribeToWidgetEvents function. Below is an example of how to subscribe to the listener:

import { subscribeToWidgetEvents } from '@embedded-banking-fundr/invoice-finance';

const subscription = subscribeToWidgetEvents(({ caseId, event, reason }) => {
  console.log('event', `${event}-${caseId}`);

  if (event === 'error' && reason) {
    console.log('error:', reason);
  }
});

// Remember to unsubscribe when you're done listening to the event
subscription.unsubscribe();

Available Events and Data

This system for handling events enables you to observe and respond to different states and interactions occurring within the lending process.

| Event Name | Description | Data | | ----------- | ------------------------------------------------------------------------------------- | ----------------------------------- | | start | Emitted when user starts the journey. | { partnerId, caseId } | | abandon | Emitted when the widget closes and the flow has not been completed. | { partnerId, caseId } | | success | Emitted when the lending process is completed. | { partnerId, caseId } | | error | Emitted when the user encountered an error. | { partnerId, caseId, reason } | | exit | Emitted when the widget closes. | { partnerId, caseId } |

If it's an error event, it will include an extra property called "reason". In such instances, the reason provided can be one of the following:

| Reason | | ------------------------- | |NEW_TO_THE_BANK | |GENERIC | |TIMEOUT | |RED_SCORE | |TRANSACTION_STATUS | |NO_CONNECTION_ID | |GET_TRANSACTIONS | |CONSENT_DECLINED | |CREATE_CONNECTION | |INSUFFICIENT_TRANSACTIONS| |TRANSACTIONS_NOT_RECENT | |CRC_CHECK_FAILED | |INVOICE_NOT_SUITABLE | |MAX_LOAN_EXCEEDED | |TRANSACTIONS_NO_MATCHES |

To trigger an error event, follow these steps:

  1. Switch the mode (in the widget component) to mock.
  2. Navigate through the app until you reach the point where you need to select a bank for transactions.
  3. Choose "RegioBank" as the bank.
  4. Proceed further to obtain an offer.
  5. A rejection screen should appear, and an error event will be emitted.