diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 145fe8bef..3cfc64ab9 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -14,15 +14,21 @@ env: jobs: pre-commit: runs-on: ubuntu-latest + permissions: + packages: read + steps: - uses: actions/checkout@v3.5.3 - name: Cache dependencies uses: actions/setup-node@v3 with: - node-version: '16' + node-version: '20' cache: 'npm' + - name: set npm auth + run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" > ~/.npmrc + - name: install node modules run: npm ci @@ -30,6 +36,8 @@ jobs: cypress: runs-on: ubuntu-latest + permissions: + packages: read # Current backend version as service container services: @@ -44,6 +52,9 @@ jobs: steps: - uses: actions/checkout@v3.5.3 + - name: set npm auth + run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" > ~/.npmrc + - uses: cypress-io/github-action@v5.8.3 env: PORT: 3001 @@ -106,9 +117,9 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v4.1.1 with: - context: . push: ${{ steps.push_check.outputs.push }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | REACT_APP_VERSION=${{ github.ref_name }} + GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..13a79428e --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@envelope-zero:registry=https://npm.pkg.github.com diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a819e650..fd6dadada 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,11 +4,12 @@ Contributions are welcome. Please note the [Code of Conduct](CODE_OF_CONDUCT.md) ## Tool & Repository setup -You will need the following tools: +You will need to: -- [pre-commit](https://pre-commit.com/) +- Install [pre-commit](https://pre-commit.com/) +- Set up a GitHub Personal Access Token to read from the GitHub package repository. Follow the steps in https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry#authenticating-with-a-personal-access-token. -Once those are installed, run `make setup` to perform the repository setup. +Once these steps are done, run `make setup` to perform the repository setup. ## Development server diff --git a/Dockerfile b/Dockerfile index da2a398ac..fb72855e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,13 @@ -FROM node:20.5.1-alpine AS builder +FROM node:20.3.1-alpine AS builder ENV NODE_ENV production WORKDIR /app # copy package.json first to avoid unnecessary npm install COPY package.json package-lock.json /app/ -RUN npm install --production + +ARG GITHUB_TOKEN +RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" > ~/.npmrc && \ + npm install --production # Copy app files COPY src /app/src diff --git a/cypress/e2e/transaction-import.cy.ts b/cypress/e2e/transaction-import.cy.ts index 66797f2fb..1025bcd15 100644 --- a/cypress/e2e/transaction-import.cy.ts +++ b/cypress/e2e/transaction-import.cy.ts @@ -35,9 +35,7 @@ describe('Transaction Import', () => { cy.contains('My Other Account') cy.contains('My Account').click() - cy.getInputFor('File').selectFile( - 'cypress/fixtures/transactions-parsed.csv' - ) + cy.getInputFor('File').selectFile('cypress/fixtures/comdirect.csv') cy.clickAndWait('Submit') @@ -163,9 +161,7 @@ describe('Transaction Import', () => { cy.awaitLoading() cy.getInputFor('Account').type('My account{enter}') - cy.getInputFor('File').selectFile( - 'cypress/fixtures/transactions-parsed.csv' - ) + cy.getInputFor('File').selectFile('cypress/fixtures/comdirect.csv') cy.clickAndWait('Submit') cy.contains('This is a duplicate of an existing transaction') diff --git a/cypress/fixtures/comdirect.csv b/cypress/fixtures/comdirect.csv new file mode 100644 index 000000000..6d291a3a1 --- /dev/null +++ b/cypress/fixtures/comdirect.csv @@ -0,0 +1,11 @@ +; +"Umsätze Verrechnungskonto ";"Zeitraum: 30 Tage"; +"Neuer Kontostand";"16,94 EUR"; + +"Buchungstag";"Wertstellung (Valuta)";"Vorgang";"Buchungstext";"Umsatz in EUR"; +"20.06.2023";"20.06.2023";"Irrevevant";"Empfänger: Non Existing Account Buchungstext: Text Ref. 000000000/0 ";"-84,76"; +"19.06.2023";"19.06.2023";"Irrevevant";"Auftraggeber: My Other Account Buchungstext: Transfer from my other account Ref. 0000000000000/0 ";"5,00"; +"16.06.2023";"16.06.2023";"Irrevevant";"Empfänger: New Account Buchungstext: REDACTED Ref. 000000000/0 ";"-784,94"; +"15.06.2023";"15.06.2023";"Irrevevant";"Auftraggeber: External Account Buchungstext: Text Ref. 000000000/0 ";"-52,03"; + +"Alter Kontostand";"16,89 EUR"; diff --git a/cypress/fixtures/transactions-parsed.csv b/cypress/fixtures/transactions-parsed.csv deleted file mode 100644 index bb3558940..000000000 --- a/cypress/fixtures/transactions-parsed.csv +++ /dev/null @@ -1,5 +0,0 @@ -Date,Payee,Memo,Outflow,Inflow -06/20/2023,Non Existing Account,Text,84.76, -06/19/2023,My Other Account,Transfer from my other account,,5.00 -06/16/2023,New Account,REDACTED,784.94, -06/15/2023,External Account,Text,52.03, diff --git a/package-lock.json b/package-lock.json index 5320ead01..c541662e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "name": "envelope-zero-frontend", "dependencies": { + "@envelope-zero/ynap-parsers": "1.15.11", "@headlessui/react": "1.7.16", "@heroicons/react": "2.0.18", "@tailwindcss/forms": "0.5.4", @@ -16,6 +17,7 @@ "@types/node": "18.17.5", "@types/react": "18.2.20", "@types/react-dom": "18.2.7", + "buffer": "6.0.3", "flowbite": "1.8.1", "flowbite-react": "0.5.0", "http-proxy-middleware": "2.0.6", @@ -2303,6 +2305,25 @@ "ms": "^2.1.1" } }, + "node_modules/@envelope-zero/ynap-parsers": { + "version": "1.15.11", + "resolved": "https://npm.pkg.github.com/download/@envelope-zero/ynap-parsers/1.15.11/b0a58550aa25ec7c951ab18141501146412a41de", + "integrity": "sha512-sQCVJPeGaW/RmUoYqnNoQxjzwyiMe9gRBiUyhcLJrWbLE7AWr8HZCl3PgUEFPRai8ArXsptcXhteBE4yxhdmBQ==", + "license": "MIT", + "dependencies": { + "buffer": "6.0.3", + "date-fns": "2.30.0", + "iban": "0.0.14", + "iconv-lite": "0.6.3", + "jschardet": "3.0.0", + "lodash": "4.17.21", + "mdn-polyfills": "5.20.0", + "mt940-js": "1.0.0", + "papaparse": "5.4.1", + "slugify": "1.6.6", + "xlsx": "^0.18.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", @@ -4872,6 +4893,14 @@ "node": ">=8.9" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -5555,7 +5584,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -5759,10 +5787,9 @@ } }, "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -5779,7 +5806,7 @@ ], "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "node_modules/buffer-crc32": { @@ -5916,6 +5943,18 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -6119,6 +6158,14 @@ "node": ">= 4.0" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -6354,6 +6401,17 @@ "node": ">=10" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6854,6 +6912,30 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/cypress/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/cypress/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -7025,6 +7107,21 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.11.5", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", @@ -9000,6 +9097,14 @@ "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -9701,6 +9806,11 @@ "@babel/runtime": "^7.22.5" } }, + "node_modules/iban": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/iban/-/iban-0.0.14.tgz", + "integrity": "sha512-+rocNKk+Ga9m8Lr9fTMWd+87JnsBrucm0ZsIx5ROOarZlaDLmd+FKdbtvb0XyoBw9GAFOYG2GuLqoNB16d+p3w==" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -9743,7 +9853,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -12406,6 +12515,14 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "node_modules/jschardet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.0.0.tgz", + "integrity": "sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -12971,6 +13088,11 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" }, + "node_modules/mdn-polyfills": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/mdn-polyfills/-/mdn-polyfills-5.20.0.tgz", + "integrity": "sha512-AbTv1ytcoOUAkxw6u5oo2QPf27kEZgxBAQr49jFb4i2VnTnFGfJbcIQ9UDBOdfNECeXsgkYFwB2BkdeTfOzztw==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -13205,6 +13327,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/mt940-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mt940-js/-/mt940-js-1.0.0.tgz", + "integrity": "sha512-9iFCkaGoUbo8FfkchMyMsUBxwmOVQbIQpgc7C0tHf6xDSzv+soVvx4PNNng/eQm/vFvCGl7ot4zJRK7Zs4veww==" + }, "node_modules/multicast-dns": { "version": "7.2.4", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.4.tgz", @@ -13612,6 +13739,11 @@ "node": ">=6" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -16416,6 +16548,14 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -16549,6 +16689,17 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -18239,6 +18390,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -18745,6 +18912,26 @@ } } }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -20338,6 +20525,24 @@ } } }, + "@envelope-zero/ynap-parsers": { + "version": "1.15.11", + "resolved": "https://npm.pkg.github.com/download/@envelope-zero/ynap-parsers/1.15.11/b0a58550aa25ec7c951ab18141501146412a41de", + "integrity": "sha512-sQCVJPeGaW/RmUoYqnNoQxjzwyiMe9gRBiUyhcLJrWbLE7AWr8HZCl3PgUEFPRai8ArXsptcXhteBE4yxhdmBQ==", + "requires": { + "buffer": "6.0.3", + "date-fns": "2.30.0", + "iban": "0.0.14", + "iconv-lite": "0.6.3", + "jschardet": "3.0.0", + "lodash": "4.17.21", + "mdn-polyfills": "5.20.0", + "mt940-js": "1.0.0", + "papaparse": "5.4.1", + "slugify": "1.6.6", + "xlsx": "^0.18.0" + } + }, "@eslint/eslintrc": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", @@ -22257,6 +22462,11 @@ "regex-parser": "^2.2.11" } }, + "adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==" + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -22747,8 +22957,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "batch": { "version": "0.6.1", @@ -22899,13 +23108,12 @@ } }, "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "buffer-crc32": { @@ -22995,6 +23203,15 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "requires": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -23146,6 +23363,11 @@ "q": "^1.1.2" } }, + "codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -23327,6 +23549,11 @@ "yaml": "^1.10.0" } }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -23672,6 +23899,16 @@ "color-convert": "^2.0.1" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -23799,6 +24036,14 @@ "whatwg-url": "^8.0.0" } }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, "dayjs": { "version": "1.11.5", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", @@ -25256,6 +25501,11 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" + }, "fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -25756,6 +26006,11 @@ "@babel/runtime": "^7.22.5" } }, + "iban": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/iban/-/iban-0.0.14.tgz", + "integrity": "sha512-+rocNKk+Ga9m8Lr9fTMWd+87JnsBrucm0ZsIx5ROOarZlaDLmd+FKdbtvb0XyoBw9GAFOYG2GuLqoNB16d+p3w==" + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -25786,8 +26041,7 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { "version": "5.2.0", @@ -27689,6 +27943,11 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "jschardet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.0.0.tgz", + "integrity": "sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==" + }, "jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -28113,6 +28372,11 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" }, + "mdn-polyfills": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/mdn-polyfills/-/mdn-polyfills-5.20.0.tgz", + "integrity": "sha512-AbTv1ytcoOUAkxw6u5oo2QPf27kEZgxBAQr49jFb4i2VnTnFGfJbcIQ9UDBOdfNECeXsgkYFwB2BkdeTfOzztw==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -28272,6 +28536,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "mt940-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mt940-js/-/mt940-js-1.0.0.tgz", + "integrity": "sha512-9iFCkaGoUbo8FfkchMyMsUBxwmOVQbIQpgc7C0tHf6xDSzv+soVvx4PNNng/eQm/vFvCGl7ot4zJRK7Zs4veww==" + }, "multicast-dns": { "version": "7.2.4", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.4.tgz", @@ -28553,6 +28822,11 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -30455,6 +30729,11 @@ } } }, + "slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==" + }, "sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -30569,6 +30848,14 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "requires": { + "frac": "~1.1.2" + } + }, "sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -31788,6 +32075,16 @@ "is-typed-array": "^1.1.10" } }, + "wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==" + }, + "word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==" + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -32245,6 +32542,20 @@ "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "requires": {} }, + "xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "requires": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + } + }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", diff --git a/package.json b/package.json index 4c3d4a0da..33780486b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "envelope-zero-frontend", "dependencies": { + "@envelope-zero/ynap-parsers": "1.15.11", "@headlessui/react": "1.7.16", "@heroicons/react": "2.0.18", "@tailwindcss/forms": "0.5.4", @@ -11,6 +12,7 @@ "@types/node": "18.17.5", "@types/react": "18.2.20", "@types/react-dom": "18.2.7", + "buffer": "6.0.3", "flowbite": "1.8.1", "flowbite-react": "0.5.0", "http-proxy-middleware": "2.0.6", @@ -50,10 +52,7 @@ "start": "react-scripts start", "build": "react-scripts build", "server:dev": "docker-compose --project-name frontend-dev --file docker-compose-dev.yml up", - "server:test": "docker-compose --project-name frontend-test --file docker-compose-test.yml up --detach", - "server:test:stop": "docker-compose --project-name frontend-test --file docker-compose-test.yml down", - "server:test:restart": "docker-compose --project-name frontend-test --file docker-compose-test.yml restart", - "server:test:logs": "docker-compose --project-name frontend-test --file docker-compose-test.yml logs --follow", + "server:test": "docker-compose --project-name frontend-test --file docker-compose-test.yml up", "test": "cypress run", "test:watch": "cypress open", "eject": "react-scripts eject", diff --git a/src/components/TransactionImport/Form.tsx b/src/components/TransactionImport/Form.tsx index 89090600b..2c6b0b564 100644 --- a/src/components/TransactionImport/Form.tsx +++ b/src/components/TransactionImport/Form.tsx @@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next' import { useState } from 'react' import { Link } from 'react-router-dom' import { Account, TransactionPreview, Translation } from '../../types' +import { parseFile } from '@envelope-zero/ynap-parsers' import { checkStatus, parseJSON } from '../../lib/fetch-helper' import Error from '../Error' import FormFields from '../FormFields' @@ -29,23 +30,40 @@ const Form = ({ accounts, isLoading, setIsLoading, setResult }: Props) => { event.preventDefault() setIsLoading(true) + const file = (event.target as any).file.files[0] // TODO: without `any` - fetch(`/api/v1/import/ynab-import-preview?accountId=${accountId}`, { - method: 'POST', - body: new FormData(event.target as HTMLFormElement), - }) - .then(checkStatus) - .then(parseJSON) - .then(body => { - setIsLoading(false) - if (error) { - setError('') - } - setResult(body.data, accountId) + parseFile(file) + .then(result => { + // Get the data and transform it to FormData for the backend + const data = new FormData() + data.append( + 'file', + new File([new Blob([result[0].data])], 'ynap-transactions.csv', { + type: 'text/csv;charset=utf-8;', + }) + ) + + fetch(`/api/v1/import/ynab-import-preview?accountId=${accountId}`, { + method: 'POST', + body: data, + }) + .then(checkStatus) + .then(parseJSON) + .then(body => { + setIsLoading(false) + if (error) { + setError('') + } + setResult(body.data, accountId) + }) + .catch(error => { + setIsLoading(false) + setError(error.message) + }) }) .catch(error => { setIsLoading(false) - setError(error.message) + setError(error) }) }} > @@ -64,20 +82,12 @@ const Form = ({ accounts, isLoading, setIsLoading, setResult }: Props) => { ) : ( <> -

- {t('transactions.import.description')} -

-

{t('transactions.import.howTo.title')}

-
    - {['download', 'parse', 'upload'].map(step => ( -
  1. - ))} -
+

groups={[{ items: accounts }]} diff --git a/src/translations/en.json b/src/translations/en.json index c1595df04..13d1918d9 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -88,20 +88,13 @@ "import": { "importTransactions": "Import Transactions", "account": "Account", - "description": "Import a list of transactions (for example a downloaded bank statement). \n\nYou will be able to review the parsed transactions before they are saved.", - "ynapCredits": "Uploads are parsed in your browser, powered by YNAP. A list of all currently supported banks can be found here.", + "description": "Import a list of transactions, for example a downloaded bank statement.\n\nYou will be able to review the transactions before they are saved.\n\nUploads are parsed in your browser, powered by YNAP, and by Envelope Zero. A list of all currently supported banks can be found here.", "previous": "Previous Transaction", "next": "Next Transaction", "importSuccess": "Successfully imported", "deleteSuccess": "Successfully deleted", "duplicateDetected": "This is a duplicate of an existing transaction", - "complete": "Import complete", - "howTo": { - "title": "How To Import", - "download": "Download a .CSV export of your transactions from your bank", - "parse": "Parse that file using YNAP (A list of all currently supported banks can be found here)", - "upload": "Upload the parsed file here:" - } + "complete": "Import complete" }, "from": "From", "to": "To",