diff options
Diffstat (limited to 'packages/merchant-backend-ui')
77 files changed, 18444 insertions, 0 deletions
diff --git a/packages/merchant-backend-ui/.gitignore b/packages/merchant-backend-ui/.gitignore new file mode 100644 index 000000000..a6ee22df2 --- /dev/null +++ b/packages/merchant-backend-ui/.gitignore @@ -0,0 +1,9 @@ +/build +/size-plugin.json +/storybook-static +/docs +/single +/coverage +/dist +/.rollup.cache +/.linaria-cache diff --git a/packages/merchant-backend-ui/.storybook/.babelrc b/packages/merchant-backend-ui/.storybook/.babelrc new file mode 100644 index 000000000..610b6f339 --- /dev/null +++ b/packages/merchant-backend-ui/.storybook/.babelrc @@ -0,0 +1,25 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + /** + * + * @author Sebastian Javier Marchano (sebasjm) + */ +{ + "presets": [ + "preact-cli/babel" + ] +}
\ No newline at end of file diff --git a/packages/merchant-backend-ui/.storybook/main.js b/packages/merchant-backend-ui/.storybook/main.js new file mode 100644 index 000000000..5497a6510 --- /dev/null +++ b/packages/merchant-backend-ui/.storybook/main.js @@ -0,0 +1,82 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + + +module.exports = { + "stories": [ + "../src/**/*.stories.mdx", + "../src/**/*.stories.@(js|jsx|ts|tsx)" + ], + "addons": [ + "@storybook/preset-scss", + "@storybook/addon-a11y", + "@storybook/addon-essentials" //docs, control, actions, viewpot, toolbar, background + ], + // sb does not yet support new jsx transform by default + // https://github.com/storybookjs/storybook/issues/12881 + // https://github.com/storybookjs/storybook/issues/12952 + babel: async (options) => ({ + ...options, + presets: [ + ...options.presets, + [ + '@babel/preset-react', { + runtime: 'automatic', + }, + 'preset-react-jsx-transform' + ], + "@linaria", + ], + }), + webpackFinal: (config) => { + // should be removed after storybook 6.3 + // https://github.com/storybookjs/storybook/issues/12853#issuecomment-821576113 + config.resolve.alias = { + react: "preact/compat", + "react-dom": "preact/compat", + }; + + // we need to add @linaria loader AFTER the babel-loader + // https://github.com/callstack/linaria/blob/master/docs/BUNDLERS_INTEGRATION.md#webpack + config.module.rules[0] = { + ...(config.module.rules[0]), + loader: undefined, // Disable the predefined babel-loader on the rule + use: [ + { + ...(config.module.rules[0].use[0]), + loader: 'babel-loader', + }, + { + loader: '@linaria/webpack-loader', + options: { + sourceMap: true, //always true since this is dev + babelOptions: { + presets: config.module.rules[0].use[0].options.presets, + } + // Pass the current babel options to linaria's babel instance + } + } + ] + }; + + return config; + }, +}
\ No newline at end of file diff --git a/packages/merchant-backend-ui/.storybook/preview.js b/packages/merchant-backend-ui/.storybook/preview.js new file mode 100644 index 000000000..a9cc4c39a --- /dev/null +++ b/packages/merchant-backend-ui/.storybook/preview.js @@ -0,0 +1,73 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { ConfigContextProvider } from '../src/context/config' +import { InstanceContextProvider } from '../src/context/instance' +import { TranslationProvider } from '../src/context/translation' +import { BackendContextProvider } from '../src/context/backend' +import { h } from 'preact'; + +const mockConfig = { + backendURL: 'http://demo.taler.net', + currency: 'TESTKUDOS' +} + +const mockInstance = { + id: 'instance-id', + token: 'instance-token', + admin: false, +} + +const mockBackend = { + url: 'http://merchant.url', + token: 'default-token', + triedToLog: false, +} + +export const parameters = { + controls: { expanded: true }, + // actions: { argTypesRegex: "^on.*" }, +} + +export const globalTypes = { + locale: { + name: 'Locale', + description: 'Internationalization locale', + defaultValue: 'en', + toolbar: { + icon: 'globe', + items: [ + { value: 'en', right: 'πΊπΈ', title: 'English' }, + { value: 'es', right: 'πͺπΈ', title: 'Spanish' }, + ], + }, + }, +}; + +export const decorators = [ + (Story, { globals }) => <TranslationProvider initial='en' forceLang={globals.locale}> + <Story /> + </TranslationProvider>, + (Story) => <ConfigContextProvider value={mockConfig}> + <Story /> + </ConfigContextProvider>, + (Story) => <InstanceContextProvider value={mockInstance}> + <Story /> + </InstanceContextProvider>, + (Story) => <BackendContextProvider defaultUrl={mockBackend.url}> + <Story /> + </BackendContextProvider>, +]; diff --git a/packages/merchant-backend-ui/README.md b/packages/merchant-backend-ui/README.md new file mode 100644 index 000000000..16cbd0b9a --- /dev/null +++ b/packages/merchant-backend-ui/README.md @@ -0,0 +1,30 @@ +Merchant Backend pages + +# Description + +This project generate 5 templates for the merchant backend: + + * DepletedTip + * OfferRefund + * OfferTip + * RequestPayment + * ShowOrderDetails + +This pages are to be serve from the merchant-backend service and will be queried for browser that may or may not have javascript enabled, so we are going to do server side rendering. +The merchant-backend service is currently supporting mustache library for server side rendering. +We also want the be able to create a more interactive design if the browser have javascript enabled, so the pages will be serve with all the infromation in the html but also in javascript. + +In this scenario, we are using jsx to build the template of the page that will be build-time rendered into the mustache template. This template can the be deployed into a merchant-backend that will complete the information before send it to the browser. + +# Building + +The building process can be executed with `pnpm build` + +# Testing + +This project is using a javascript implementation of mustache that can be executed with the command `pnpm render-examples`. +This script will take the pages previously built in `dist/pages` directory and the examples definition in the `src/pages/[exampleName].examples.ts` files and render a to-be-sent-to-the-user page like the merchant would do. +This examples will be saved invidivualy into directory `dist/examples` and should be opened with your testing browser. +Testing should be done with javascript enabled and javascript disabled, both should look ok. + + diff --git a/packages/merchant-backend-ui/contrib/po2ts b/packages/merchant-backend-ui/contrib/po2ts new file mode 100755 index 000000000..a135da61b --- /dev/null +++ b/packages/merchant-backend-ui/contrib/po2ts @@ -0,0 +1,42 @@ +#!/usr/bin/env node +/* + This file is part of GNU Taler + (C) 2020 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * Convert a <lang>.po file into a JavaScript / TypeScript expression. + */ + +const po2json = require("po2json"); + +const filename = process.argv[2]; + +if (!filename) { + console.error("error: missing filename"); + process.exit(1); +} + +const m = filename.match(/([a-zA-Z0-9-_]+).po/); + +if (!m) { + console.error("error: unexpected filename (expected <lang>.po)"); + process.exit(1); +} + +const lang = m[1]; +const pojson = po2json.parseFileSync(filename, { format: "jed1.x", fuzzy: true }); +const s = + "strings['" + lang + "'] = " + JSON.stringify(pojson, null, " ") + ";\n"; +console.log(s); diff --git a/packages/merchant-backend-ui/copyleft-header.js b/packages/merchant-backend-ui/copyleft-header.js new file mode 100644 index 000000000..0794cb839 --- /dev/null +++ b/packages/merchant-backend-ui/copyleft-header.js @@ -0,0 +1,15 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ diff --git a/packages/merchant-backend-ui/package.json b/packages/merchant-backend-ui/package.json new file mode 100644 index 000000000..4a30def96 --- /dev/null +++ b/packages/merchant-backend-ui/package.json @@ -0,0 +1,144 @@ +{ + "private": true, + "name": "merchant-backend", + "version": "0.0.4", + "license": "MIT", + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w", + "render-examples": "ts-node -O '{\"module\": \"commonjs\"}' -T render-examples.ts dist/pages dist/examples", + "lint-check": "eslint '{src,tests}/**/*.{js,jsx,ts,tsx}'", + "lint-fix": "eslint --fix '{src,tests}/**/*.{js,jsx,ts,tsx}'", + "test": "jest ./tests", + "dev-test": "jest ./tests --watch", + "typedoc": "typedoc src", + "clean": "rimraf build storybook-static docs single dist", + "serve-dist": "sirv --port ${PORT:=8080} --cors --single dist", + "build-storybook": "build-storybook", + "storybook": "start-storybook -p 6006" + }, + "engines": { + "node": ">=12", + "pnpm": ">=5" + }, + "eslintConfig": { + "parser": "@typescript-eslint/parser", + "extends": [ + "preact", + "plugin:@typescript-eslint/recommended" + ], + "plugins": [ + "header" + ], + "rules": { + "header/header": [ + 2, + "copyleft-header.js" + ] + }, + "ignorePatterns": [ + "build/" + ] + }, + "dependencies": { + "@gnu-taler/taler-util": "workspace:*", + "axios": "^0.21.1", + "date-fns": "^2.21.1", + "history": "4.10.1", + "jed": "^1.1.1", + "preact": "^10.5.13", + "preact-router": "^3.2.1", + "qrcode-generator": "^1.4.4", + "swr": "^0.5.5", + "yup": "^0.32.9" + }, + "devDependencies": { + "@babel/core": "^7.13.16", + "@babel/plugin-transform-react-jsx-source": "^7.12.13", + "@creativebulma/bulma-tooltip": "^1.2.0", + "@gnu-taler/pogen": "^0.0.5", + "@linaria/babel-preset": "^3.0.0-beta.4", + "@linaria/core": "^3.0.0-beta.4", + "@linaria/react": "^3.0.0-beta.7", + "@linaria/rollup": "^3.0.0-beta.7", + "@linaria/shaker": "^3.0.0-beta.7", + "@linaria/webpack-loader": "^3.0.0-beta.7", + "@rollup/plugin-alias": "^3.1.5", + "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-commonjs": "^20.0.0", + "@rollup/plugin-html": "^0.2.3", + "@rollup/plugin-image": "^2.1.1", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-replace": "^3.0.0", + "@rollup/plugin-typescript": "^8.2.5", + "@storybook/addon-a11y": "^6.2.9", + "@storybook/addon-actions": "^6.2.9", + "@storybook/addon-essentials": "^6.2.9", + "@storybook/addon-links": "^6.2.9", + "@storybook/preact": "^6.2.9", + "@storybook/preset-scss": "^1.0.3", + "@testing-library/preact": "^2.0.1", + "@testing-library/preact-hooks": "^1.1.0", + "@types/enzyme": "^3.10.8", + "@types/history": "^4.7.8", + "@types/jest": "^26.0.23", + "@types/mocha": "^8.2.2", + "@types/mustache": "^4.1.2", + "@typescript-eslint/eslint-plugin": "^4.22.0", + "@typescript-eslint/parser": "^4.22.0", + "babel-loader": "^8.2.2", + "base64-inline-loader": "^1.1.1", + "bulma": "^0.9.2", + "bulma-checkbox": "^1.1.1", + "bulma-radio": "^1.1.1", + "bulma-responsive-tables": "^1.2.3", + "bulma-switch-control": "^1.1.1", + "bulma-timeline": "^3.0.4", + "bulma-upload-control": "^1.2.0", + "dotenv": "^8.2.0", + "enzyme": "^3.11.0", + "enzyme-adapter-preact-pure": "^3.1.0", + "eslint": "^7.25.0", + "eslint-config-preact": "^1.1.4", + "eslint-plugin-header": "^3.1.1", + "html-webpack-inline-chunk-plugin": "^1.1.1", + "html-webpack-inline-source-plugin": "0.0.10", + "html-webpack-skip-assets-plugin": "^1.0.1", + "inline-chunk-html-plugin": "^1.1.1", + "jest": "^26.6.3", + "jest-preset-preact": "^4.0.2", + "mustache": "^4.2.0", + "po2json": "^0.4.5", + "preact-cli": "^3.0.5", + "preact-render-to-json": "^3.6.6", + "preact-render-to-string": "^5.1.19", + "rimraf": "^3.0.2", + "rollup": "^2.56.3", + "rollup-plugin-bundle-html": "^0.2.2", + "rollup-plugin-css-only": "^3.1.0", + "sass": "^1.32.13", + "sass-loader": "10.1.1", + "script-ext-html-webpack-plugin": "^2.1.5", + "sirv-cli": "^1.0.11", + "tslib": "^2.3.1", + "typedoc": "^0.20.36", + "typescript": "^4.2.4" + }, + "jest": { + "preset": "jest-preset-preact", + "transformIgnorePatterns": [ + "node_modules/.pnpm/(?!(@gnu-taler\\+taler-util))", + "\\.pnp\\.[^\\/]+$" + ], + "setupFiles": [ + "<rootDir>/tests/__mocks__/browserMocks.ts", + "<rootDir>/tests/__mocks__/setupTests.ts" + ], + "moduleNameMapper": { + "\\.(css|less)$": "identity-obj-proxy" + }, + "transform": { + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|po)$": "<rootDir>/tests/__mocks__/fileTransformer.js" + } + } +} diff --git a/packages/merchant-backend-ui/render-examples.ts b/packages/merchant-backend-ui/render-examples.ts new file mode 100644 index 000000000..47300ab8f --- /dev/null +++ b/packages/merchant-backend-ui/render-examples.ts @@ -0,0 +1,83 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import mustache from "mustache"; +import fs from "fs"; +import { format, formatDuration, intervalToDuration } from "date-fns"; + +/** + * This script will emulate what the merchant backend will do when being requested + * +*/ + +const sourceDirectory = process.argv[2] +const destDirectory = process.argv[3] + +if (!sourceDirectory || !destDirectory) { + console.log('usage: render-mustache <source-directory> <dest-directory>') + process.exit(1); +} + +if (!fs.existsSync(destDirectory)) { + fs.mkdirSync(destDirectory); +} + +/** + * Load all the html files + */ +const files = fs.readdirSync(sourceDirectory).filter(f => /.html/.test(f)) + +files.forEach(file => { + const html = fs.readFileSync(`${sourceDirectory}/${file}`, 'utf8') + + const testName = file.replace('.html', '') + if (testName !== 'ShowOrderDetails') return; + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { exampleData } = require(`./src/pages/${testName}.examples`) + + Object.keys(exampleData).forEach(exampleName => { + const example = exampleData[exampleName] + + //enhance the example with more information + example.contract_terms_json = () => JSON.stringify(example.contract_terms); + example.contract_terms.timestamp_str = () => example.contract_terms.timestamp && format(example.contract_terms.timestamp.t_s, 'dd MMM yyyy HH:mm:ss'); + + example.contract_terms.hasProducts = () => example.contract_terms.products?.length > 0; + example.contract_terms.hasAuditors = () => example.contract_terms.auditors?.length > 0; + example.contract_terms.hasExchanges = () => example.contract_terms.exchanges?.length > 0; + + example.contract_terms.products.forEach(p => { + p.delivery_date_str = () => p.delivery_date && format(p.delivery_date.t_s, 'dd MM yyyy HH:mm:ss') + p.hasTaxes = () => p.taxes?.length > 0 + }) + example.contract_terms.has_delivery_info = () => example.contract_terms.delivery_date || example.contract_terms.delivery_location + + example.contract_terms.delivery_date_str = () => example.contract_terms.delivery_date && format(example.contract_terms.delivery_date.t_s, 'dd MM yyyy HH:mm:ss') + example.contract_terms.pay_deadline_str = () => example.contract_terms.pay_deadline && format(example.contract_terms.pay_deadline.t_s, 'dd MM yyyy HH:mm:ss') + example.contract_terms.wire_transfer_deadline_str = () => example.contract_terms.wire_transfer_deadline && format(example.contract_terms.wire_transfer_deadline.t_s, 'dd MM yyyy HH:mm:ss') + example.contract_terms.refund_deadline_str = () => example.contract_terms.refund_deadline && format(example.contract_terms.refund_deadline.t_s, 'dd MM yyyy HH:mm:ss') + example.contract_terms.auto_refund_str = () => example.contract_terms.auto_refund && formatDuration(intervalToDuration({ start: 0, end: example.contract_terms.auto_refund.d_us })) + + const output = mustache.render(html, example); + + fs.writeFileSync(`${destDirectory}/${testName}.${exampleName}.html`, output) + }) +}) diff --git a/packages/merchant-backend-ui/rollup.config.js b/packages/merchant-backend-ui/rollup.config.js new file mode 100644 index 000000000..f5227ba74 --- /dev/null +++ b/packages/merchant-backend-ui/rollup.config.js @@ -0,0 +1,112 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +// rollup.config.js +import linaria from '@linaria/rollup'; +import nodeResolve from "@rollup/plugin-node-resolve"; +import alias from "@rollup/plugin-alias"; +import image from '@rollup/plugin-image'; +import json from "@rollup/plugin-json"; +import ts from "@rollup/plugin-typescript"; +import replace from "@rollup/plugin-replace"; +import css from 'rollup-plugin-css-only'; +import html from '@rollup/plugin-html'; +import commonjs from "@rollup/plugin-commonjs"; + + + +const template = async ({ + files, +}) => { + const scripts = (files.js || []).map(({ code }) => `<script>${code}</script>`).join('\n'); + const css = (files.css || []).map(({ source }) => `<style>${source}</style>`).join('\n'); + const ssr = (files.js || []).map(({ code }) => code).join('\n'); + const page = new Function(`${ssr}; return page.buildTimeRendering();`)() + return ` +<!doctype html> +<html> + <head> + ${page.head} + ${css} + </head> + <script id="built_time_data"> + </script> + <body> + ${page.body} + ${scripts} + <script>page.mount()</script> + </body> +</html>`; +}; + +const makePlugins = (name) => [ + alias({ + entries: [ + { find: 'react', replacement: 'preact/compat' }, + { find: 'react-dom', replacement: 'preact/compat' } + ] + }), + + replace({ + "process.env.NODE_ENV": JSON.stringify("production"), + preventAssignment: true, + }), + + commonjs({ + include: [/node_modules/, /dist/], + extensions: [".js"], + ignoreGlobal: true, + sourceMap: true, + }), + + nodeResolve({ + browser: true, + preferBuiltins: true, + }), + + json(), + image(), + + linaria({ + sourceMap: process.env.NODE_ENV !== 'production', + }), + css(), + ts({ + sourceMap: false, + outputToFilesystem: false, + }), + html({ template, fileName: name }), +]; + + +const pageDefinition = (name) => ({ + input: `src/pages/${name}.tsx`, + output: { + file: `dist/pages/${name}.js`, + format: "iife", + exports: 'named', + name: 'page', + }, + plugins: makePlugins(`${name}.html`), +}); + +export default [ + pageDefinition("OfferTip"), + pageDefinition("OfferRefund"), + pageDefinition("DepletedTip"), + pageDefinition("RequestPayment"), + pageDefinition("ShowOrderDetails"), +] diff --git a/packages/merchant-backend-ui/src/assets/empty.png b/packages/merchant-backend-ui/src/assets/empty.png Binary files differnew file mode 100644 index 000000000..5120d3138 --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/empty.png diff --git a/packages/merchant-backend-ui/src/assets/icons/android-chrome-192x192.png b/packages/merchant-backend-ui/src/assets/icons/android-chrome-192x192.png Binary files differnew file mode 100644 index 000000000..93ebe2e2c --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/android-chrome-192x192.png diff --git a/packages/merchant-backend-ui/src/assets/icons/android-chrome-512x512.png b/packages/merchant-backend-ui/src/assets/icons/android-chrome-512x512.png Binary files differnew file mode 100644 index 000000000..52d1623ea --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/android-chrome-512x512.png diff --git a/packages/merchant-backend-ui/src/assets/icons/apple-touch-icon.png b/packages/merchant-backend-ui/src/assets/icons/apple-touch-icon.png Binary files differnew file mode 100644 index 000000000..254e4bb4d --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/apple-touch-icon.png diff --git a/packages/merchant-backend-ui/src/assets/icons/favicon-16x16.png b/packages/merchant-backend-ui/src/assets/icons/favicon-16x16.png Binary files differnew file mode 100644 index 000000000..e81177dcb --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/favicon-16x16.png diff --git a/packages/merchant-backend-ui/src/assets/icons/favicon-32x32.png b/packages/merchant-backend-ui/src/assets/icons/favicon-32x32.png Binary files differnew file mode 100644 index 000000000..40e9b5b47 --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/favicon-32x32.png diff --git a/packages/merchant-backend-ui/src/assets/icons/languageicon.svg b/packages/merchant-backend-ui/src/assets/icons/languageicon.svg new file mode 100644 index 000000000..22d58da65 --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/languageicon.svg @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 2411.2 2794" style="enable-background:new 0 0 2411.2 2794;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#FFFFFF;}
+ .st1{fill-rule:evenodd;clip-rule:evenodd;}
+ .st2{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
+</style>
+<g id="Layer_2">
+</g>
+<g id="Layer_x5F_1_x5F_1">
+ <g>
+ <polygon points="1204.6,359.2 271.8,30 271.8,2060.1 1204.6,1758.3 "/>
+ <polygon class="st0" points="1182.2,358.1 2150.6,29 2150.6,2059 1182.2,1757.3 "/>
+ <polygon class="st0" points="30,2415.4 1182.2,2031.4 1182.2,357.9 30,742 "/>
+ <polygon points="1707.2,2440.7 1870.5,2709.4 1956.6,2459.8 "/>
+ <g>
+ <path d="M421.7,934.8c-6.1-6,8,49.1,27.6,68.9c34.8,35.1,61.9,39.6,76.4,40.2c32,1.3,71.5-8,94.9-17.8
+ c22.7-9.7,62.4-30,77.5-59.6c3.2-6.3,11.9-17,6.4-43.2c-4.2-20.2-17-27.3-32.7-26.2c-15.7,1.1-63.2,13.7-86.1,20.8
+ c-23,7-70.3,21.4-90.9,25.8C474.3,948.2,429,941.7,421.7,934.8z"/>
+ <path d="M1003.1,1593.7c-9.1-3.3-196.9-81.1-223.6-93.9c-21.8-10.5-75.2-33.1-100.4-43.3c70.8-109.2,115.5-191.6,121.5-204.1
+ c11-23,86-169.6,87.7-178.7c1.7-9.1,3.8-42.9,2.2-51c-1.7-8.2-29.1,7.6-66.4,20.2c-37.4,12.6-108.4,58.8-135.8,64.6
+ c-27.5,5.7-115.5,39.1-160.5,54c-45,14.9-130.2,40.9-165.2,50.4c-35.1,9.5-65.7,10.2-85.3,16.2c0,0,2.6,27.5,7.8,35.7
+ c5.2,8.2,23.7,28.4,45.3,34.1c21.6,5.7,57.3,3.4,73.6-0.3c16.3-3.8,44.4-17.5,48.2-23.6c3.8-6.1-2-24.9,4.5-30.6
+ c6.5-5.6,92.2-25.7,124.6-35.4c32.4-10,156.3-52.6,173.1-50.5c-5.3,17.7-105,215.1-137.1,274c-32.1,58.9-218.6,318-258.3,363.6
+ c-30.1,34.7-103.2,123.5-128.5,143.6c6.4,1.8,51.6-2.1,59.9-7.2c51.3-31.6,136.9-138.1,164.4-170.5
+ c81.9-96,153.8-196.8,210.8-283.4h0.1c11.1,4.6,100.9,77.8,124.4,94c23.4,16.2,115.9,67.8,136,76.4c20,8.7,97.1,44.2,100.3,32.2
+ C1029.4,1668,1012.2,1597.1,1003.1,1593.7z"/>
+ </g>
+ <path class="st1" d="M569,2572c18,11,35,20,54,29c38,19,81,39,122,54c56,21,112,38,168,51c31,7,65,13,98,18c3,0,92,11,110,11h90
+ c35-3,68-5,103-10c28-4,59-9,89-16c22-5,45-10,67-17c21-6,45-14,68-22c15-5,31-12,47-18c13-6,29-13,44-19c18-8,39-19,59-29
+ c16-8,34-18,51-28c13-7,43-30,59-30c18,0,30,16,30,30c0,29-39,38-57,51c-19,13-42,23-62,34c-40,21-81,39-120,54
+ c-51,19-107,37-157,49c-19,4-38,9-57,12c-10,2-114,18-143,18h-132c-35-3-72-7-107-12c-31-5-64-11-95-18c-24-5-50-12-73-19
+ c-40-11-79-25-117-40c-69-26-141-60-209-105c-12-8-13-16-13-25c0-15,11-29,29-29C531,2546,563,2569,569,2572z"/>
+ <path class="st1" d="M1151,2009L61,2372V764l1090-363V2009z M1212,354v1680c-1,5-3,10-7,15c-2,3-6,7-9,8c-25,10-1151,388-1166,388
+ c-12,0-23-8-29-21c0-1-1-2-1-4V739c2-5,3-12,7-16c8-11,22-13,31-16c17-6,1126-378,1142-378C1190,329,1212,336,1212,354z"/>
+ <path class="st1" d="M2120,2017l-907-282V380l907-308V2017z M2181,32v2023c-1,23-17,33-32,33c-13,0-107-32-123-37
+ c-126-39-253-78-378-117c-28-9-57-18-84-27c-24-7-50-15-74-23c-107-33-216-66-323-102c-4-1-14-15-14-18V351c2-5,4-11,9-15
+ c8-9,351-123,486-168c36-13,487-168,501-168C2167,0,2181,13,2181,32z"/>
+ <polygon points="2411.2,2440.7 1199.5,2054.5 1204.6,373.2 2411.2,757.2 "/>
+ <g>
+ <path class="st2" d="M1800.3,1124.6L1681.4,1412l218.6,66.3L1800.3,1124.6z M1729,853.2l156.1,47.3l284.4,1025l-160.3-48.7
+ l-57.6-210.4L1620.2,1566l-71.3,171.4l-160.4-48.7L1729,853.2z"/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/packages/merchant-backend-ui/src/assets/icons/mstile-150x150.png b/packages/merchant-backend-ui/src/assets/icons/mstile-150x150.png Binary files differnew file mode 100644 index 000000000..9cfb889be --- /dev/null +++ b/packages/merchant-backend-ui/src/assets/icons/mstile-150x150.png diff --git a/packages/merchant-backend-ui/src/components/Footer.tsx b/packages/merchant-backend-ui/src/components/Footer.tsx new file mode 100644 index 000000000..5f2957800 --- /dev/null +++ b/packages/merchant-backend-ui/src/components/Footer.tsx @@ -0,0 +1,32 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import { h, VNode } from 'preact'; +import { FooterBar } from '../styled'; + +export function Footer(): VNode { + return <FooterBar> + <p> + <a href="https://taler.net/">Learn more about GNU Taler on our website.</a> + <p>Copyright © 2014—2021 Taler Systems SA</p> + </p> + </FooterBar> +} + diff --git a/packages/merchant-backend-ui/src/components/QR.tsx b/packages/merchant-backend-ui/src/components/QR.tsx new file mode 100644 index 000000000..29c9920bf --- /dev/null +++ b/packages/merchant-backend-ui/src/components/QR.tsx @@ -0,0 +1,41 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + import { h, VNode } from "preact"; + import { useEffect, useRef } from "preact/hooks"; + import qrcode from "qrcode-generator"; + +export function createSVG(text:string):string { + const qr = qrcode(0, 'L'); + qr.addData(text); + qr.make(); + return qr.createSvgTag({ + scalable: true, + margin: 0 + }); +} + + export function QR({ text }: { text: string; }):VNode { + const divRef = useRef<HTMLDivElement>(null); + useEffect(() => { + divRef.current.innerHTML = createSVG(text) + }); + + return <div style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center' }}> + <div style={{ width: '50%', minWidth: 200, maxWidth: 300 }} ref={divRef} /> + </div>; + } +
\ No newline at end of file diff --git a/packages/merchant-backend-ui/src/context/backend.ts b/packages/merchant-backend-ui/src/context/backend.ts new file mode 100644 index 000000000..a920d6ffc --- /dev/null +++ b/packages/merchant-backend-ui/src/context/backend.ts @@ -0,0 +1,82 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext, h, VNode } from 'preact' +import { useCallback, useContext, useState } from 'preact/hooks' +import { useBackendDefaultToken, useBackendURL } from '../hooks'; + +interface BackendContextType { + url: string; + token?: string; + triedToLog: boolean; + resetBackend: () => void; + clearAllTokens: () => void; + addTokenCleaner: (c: () => void) => void; + updateLoginStatus: (url: string, token?: string) => void; +} + +const BackendContext = createContext<BackendContextType>({ + url: '', + token: undefined, + triedToLog: false, + resetBackend: () => null, + clearAllTokens: () => null, + addTokenCleaner: () => null, + updateLoginStatus: () => null, +}) + +function useBackendContextState(defaultUrl?: string): BackendContextType { + const [url, triedToLog, changeBackend, resetBackend] = useBackendURL(defaultUrl); + const [token, _updateToken] = useBackendDefaultToken(); + const updateToken = (t?: string) => { + _updateToken(t) + } + + const tokenCleaner = useCallback(() => { updateToken(undefined) }, []) + const [cleaners, setCleaners] = useState([tokenCleaner]) + const addTokenCleaner = (c: () => void) => setCleaners(cs => [...cs, c]) + const addTokenCleanerMemo = useCallback((c: () => void) => { addTokenCleaner(c) }, [tokenCleaner]) + + const clearAllTokens = () => { + cleaners.forEach(c => c()) + for (let i = 0; i < localStorage.length; i++) { + const k = localStorage.key(i) + if (k && /^backend-token/.test(k)) localStorage.removeItem(k) + } + resetBackend() + } + + const updateLoginStatus = (url: string, token?: string) => { + changeBackend(url); + if (token) updateToken(token); + }; + + + return { url, token, triedToLog, updateLoginStatus, resetBackend, clearAllTokens, addTokenCleaner: addTokenCleanerMemo } +} + +export const BackendContextProvider = ({ children, defaultUrl }: { children: any, defaultUrl?: string }): VNode => { + const value = useBackendContextState(defaultUrl) + + return h(BackendContext.Provider, { value, children }); +} + +export const useBackendContext = (): BackendContextType => useContext(BackendContext); diff --git a/packages/merchant-backend-ui/src/context/config.ts b/packages/merchant-backend-ui/src/context/config.ts new file mode 100644 index 000000000..5cd772380 --- /dev/null +++ b/packages/merchant-backend-ui/src/context/config.ts @@ -0,0 +1,32 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext } from 'preact' +import { useContext } from 'preact/hooks' + +interface Type { + currency: string; + version: string; +} +const Context = createContext<Type>(null!) + +export const ConfigContextProvider = Context.Provider +export const useConfigContext = (): Type => useContext(Context); diff --git a/packages/merchant-backend-ui/src/context/fetch.ts b/packages/merchant-backend-ui/src/context/fetch.ts new file mode 100644 index 000000000..52a4f9c8d --- /dev/null +++ b/packages/merchant-backend-ui/src/context/fetch.ts @@ -0,0 +1,40 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, createContext, VNode, ComponentChildren } from 'preact' +import { useContext } from 'preact/hooks' +import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr'; + +interface Type { + useSWR: typeof useSWR, + useSWRInfinite: typeof useSWRInfinite, +} + +const Context = createContext<Type>({} as any) + +export const useFetchContext = (): Type => useContext(Context); +export const FetchContextProvider = ({ children }: { children: ComponentChildren }): VNode => { + return h(Context.Provider, { value: { useSWR, useSWRInfinite }, children }); +} + +export const FetchContextProviderTesting = ({ children, data }: { children: ComponentChildren, data:any }): VNode => { + return h(Context.Provider, { value: { useSWR: () => data, useSWRInfinite }, children }); +} diff --git a/packages/merchant-backend-ui/src/context/instance.ts b/packages/merchant-backend-ui/src/context/instance.ts new file mode 100644 index 000000000..fecf36426 --- /dev/null +++ b/packages/merchant-backend-ui/src/context/instance.ts @@ -0,0 +1,35 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext } from 'preact' +import { useContext } from 'preact/hooks' + +interface Type { + id: string; + token?: string; + admin?: boolean; + changeToken: (t?:string) => void; +} + +const Context = createContext<Type>({} as any) + +export const InstanceContextProvider = Context.Provider +export const useInstanceContext = (): Type => useContext(Context); diff --git a/packages/merchant-backend-ui/src/context/listener.ts b/packages/merchant-backend-ui/src/context/listener.ts new file mode 100644 index 000000000..659db0a03 --- /dev/null +++ b/packages/merchant-backend-ui/src/context/listener.ts @@ -0,0 +1,35 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext } from 'preact' +import { useContext } from 'preact/hooks' + +interface Type { + id: string; + token?: string; + admin?: boolean; + changeToken: (t?:string) => void; +} + +const Context = createContext<Type>({} as any) + +export const ListenerContextProvider = Context.Provider +export const useListenerContext = (): Type => useContext(Context); diff --git a/packages/merchant-backend-ui/src/context/translation.ts b/packages/merchant-backend-ui/src/context/translation.ts new file mode 100644 index 000000000..952a1e325 --- /dev/null +++ b/packages/merchant-backend-ui/src/context/translation.ts @@ -0,0 +1,59 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext, h, VNode } from 'preact' +import { useContext, useEffect } from 'preact/hooks' +import { useLang } from '../hooks' +import * as jedLib from "jed"; +import { strings } from "../i18n/strings"; + +interface Type { + lang: string; + handler: any; + changeLanguage: (l: string) => void; +} +const initial = { + lang: 'en', + handler: null, + changeLanguage: () => { + // do not change anything + } +} +const Context = createContext<Type>(initial) + +interface Props { + initial?: string, + children: any, + forceLang?: string +} + +export const TranslationProvider = ({ initial, children, forceLang }: Props): VNode => { + const [lang, changeLanguage] = useLang(initial) + useEffect(() => { + if (forceLang) { + changeLanguage(forceLang) + } + }) + const handler = new jedLib.Jed(strings[lang]); + return h(Context.Provider, { value: { lang, handler, changeLanguage }, children }); +} + +export const useTranslationContext = (): Type => useContext(Context);
\ No newline at end of file diff --git a/packages/merchant-backend-ui/src/css/pure-min.css b/packages/merchant-backend-ui/src/css/pure-min.css new file mode 100644 index 000000000..77217b520 --- /dev/null +++ b/packages/merchant-backend-ui/src/css/pure-min.css @@ -0,0 +1,973 @@ +/*! + Pure v2.0.3 + Copyright 2013 Yahoo! + Licensed under the BSD License. + https://github.com/pure-cs s/pure/blob/master/LICENSE.md +*/ +/*! + normalize.cs s v | MIT License | git.io/normalize + Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.cs s v8.0.1 | MIT License | github.com/necolas/normalize.cs s */ + +.talerbar { + text-align: center; +} + +html { + line-height: 1.15; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +main { + display: block; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +hr { + -webkit-box-sizing: content-box; + box-sizing: content-box; + height: 0; + overflow: visible; +} +pre { + font-family: monospace, monospace; + font-size: 1em; +} +a { + background-color: transparent; +} +abbr[title] { + border-bottom: none; + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} +b, +strong { + font-weight: bolder; +} +code, +kbd, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -0.25em; +} +sup { + top: -0.5em; +} +img { + border-style: none; +} +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0; +} +button, +input { + overflow: visible; +} +button, +select { + text-transform: none; +} +[type="button"], +[type="reset"], +[type="submit"], +button { + -webkit-appearance: button; +} +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0; +} +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText; +} +fieldset { + padding: 0.35em 0.75em 0.625em; +} +legend { + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal; +} +progress { + vertical-align: baseline; +} +textarea { + overflow: auto; +} +[type="checkbox"], +[type="radio"] { + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} +details { + display: block; +} +summary { + display: list-item; +} +template { + display: none; +} +[hidden] { + display: none; +} +html { + font-family: sans-serif; +} +.hidden, +[hidden] { + display: none !important; +} +.pure-img { + max-width: 100%; + height: auto; + display: block; +} +.pure-g { + letter-spacing: -0.31em; + text-rendering: optimizespeed; + font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-line-pack: start; + align-content: flex-start; +} +@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + table .pure-g { + display: block; + } +} +.opera-only :-o-prefocus, +.pure-g { + word-spacing: -0.43em; +} +.pure-u { + display: inline-block; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} +.pure-g [class*="pure-u"] { + font-family: sans-serif; +} +.pure-u-1, +.pure-u-1-1, +.pure-u-1-12, +.pure-u-1-2, +.pure-u-1-24, +.pure-u-1-3, +.pure-u-1-4, +.pure-u-1-5, +.pure-u-1-6, +.pure-u-1-8, +.pure-u-10-24, +.pure-u-11-12, +.pure-u-11-24, +.pure-u-12-24, +.pure-u-13-24, +.pure-u-14-24, +.pure-u-15-24, +.pure-u-16-24, +.pure-u-17-24, +.pure-u-18-24, +.pure-u-19-24, +.pure-u-2-24, +.pure-u-2-3, +.pure-u-2-5, +.pure-u-20-24, +.pure-u-21-24, +.pure-u-22-24, +.pure-u-23-24, +.pure-u-24-24, +.pure-u-3-24, +.pure-u-3-4, +.pure-u-3-5, +.pure-u-3-8, +.pure-u-4-24, +.pure-u-4-5, +.pure-u-5-12, +.pure-u-5-24, +.pure-u-5-5, +.pure-u-5-6, +.pure-u-5-8, +.pure-u-6-24, +.pure-u-7-12, +.pure-u-7-24, +.pure-u-7-8, +.pure-u-8-24, +.pure-u-9-24 { + display: inline-block; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} +.pure-u-1-24 { + width: 4.1667%; +} +.pure-u-1-12, +.pure-u-2-24 { + width: 8.3333%; +} +.pure-u-1-8, +.pure-u-3-24 { + width: 12.5%; +} +.pure-u-1-6, +.pure-u-4-24 { + width: 16.6667%; +} +.pure-u-1-5 { + width: 20%; +} +.pure-u-5-24 { + width: 20.8333%; +} +.pure-u-1-4, +.pure-u-6-24 { + width: 25%; +} +.pure-u-7-24 { + width: 29.1667%; +} +.pure-u-1-3, +.pure-u-8-24 { + width: 33.3333%; +} +.pure-u-3-8, +.pure-u-9-24 { + width: 37.5%; +} +.pure-u-2-5 { + width: 40%; +} +.pure-u-10-24, +.pure-u-5-12 { + width: 41.6667%; +} +.pure-u-11-24 { + width: 45.8333%; +} +.pure-u-1-2, +.pure-u-12-24 { + width: 50%; +} +.pure-u-13-24 { + width: 54.1667%; +} +.pure-u-14-24, +.pure-u-7-12 { + width: 58.3333%; +} +.pure-u-3-5 { + width: 60%; +} +.pure-u-15-24, +.pure-u-5-8 { + width: 62.5%; +} +.pure-u-16-24, +.pure-u-2-3 { + width: 66.6667%; +} +.pure-u-17-24 { + width: 70.8333%; +} +.pure-u-18-24, +.pure-u-3-4 { + width: 75%; +} +.pure-u-19-24 { + width: 79.1667%; +} +.pure-u-4-5 { + width: 80%; +} +.pure-u-20-24, +.pure-u-5-6 { + width: 83.3333%; +} +.pure-u-21-24, +.pure-u-7-8 { + width: 87.5%; +} +.pure-u-11-12, +.pure-u-22-24 { + width: 91.6667%; +} +.pure-u-23-24 { + width: 95.8333%; +} +.pure-u-1, +.pure-u-1-1, +.pure-u-24-24, +.pure-u-5-5 { + width: 100%; +} +.pure-button { + display: inline-block; + line-height: normal; + white-space: nowrap; + vertical-align: middle; + text-align: center; + cursor: pointer; + -webkit-user-drag: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-button::-moz-focus-inner { + padding: 0; + border: 0; +} +.pure-button-group { + letter-spacing: -0.31em; + text-rendering: optimizespeed; +} +.opera-only :-o-prefocus, +.pure-button-group { + word-spacing: -0.43em; +} +.pure-button-group .pure-button { + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} +.pure-button { + font-family: inherit; + font-size: 100%; + padding: 0.5em 1em; + color: rgba(0, 0, 0, 0.8); + border: none transparent; + background-color: #e6e6e6; + text-decoration: none; + border-radius: 2px; +} +.pure-button-hover, +.pure-button:focus, +.pure-button:hover { + background-image: -webkit-gradient( + linear, + left top, + left bottom, + from(transparent), + color-stop(40%, rgba(0, 0, 0, 0.05)), + to(rgba(0, 0, 0, 0.1)) + ); + background-image: linear-gradient( + transparent, + rgba(0, 0, 0, 0.05) 40%, + rgba(0, 0, 0, 0.1) + ); +} +.pure-button:focus { + outline: 0; +} +.pure-button-active, +.pure-button:active { + -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, + 0 0 6px rgba(0, 0, 0, 0.2) inset; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, + 0 0 6px rgba(0, 0, 0, 0.2) inset; + border-color: #000; +} +.pure-button-disabled, +.pure-button-disabled:active, +.pure-button-disabled:focus, +.pure-button-disabled:hover, +.pure-button[disabled] { + border: none; + background-image: none; + opacity: 0.4; + cursor: not-allowed; + -webkit-box-shadow: none; + box-shadow: none; + pointer-events: none; +} +.pure-button-hidden { + display: none; +} +.pure-button-primary, +.pure-button-selected, +a.pure-button-primary, +a.pure-button-selected { + background-color: #0078e7; + color: #fff; +} +.pure-button-group .pure-button { + margin: 0; + border-radius: 0; + border-right: 1px solid rgba(0, 0, 0, 0.2); +} +.pure-button-group .pure-button:first-child { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} +.pure-button-group .pure-button:last-child { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-right: none; +} +.pure-form input[type="color"], +.pure-form input[type="date"], +.pure-form input[type="datetime-local"], +.pure-form input[type="datetime"], +.pure-form input[type="email"], +.pure-form input[type="month"], +.pure-form input[type="number"], +.pure-form input[type="password"], +.pure-form input[type="search"], +.pure-form input[type="tel"], +.pure-form input[type="text"], +.pure-form input[type="time"], +.pure-form input[type="url"], +.pure-form input[type="week"], +.pure-form select, +.pure-form textarea { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + -webkit-box-shadow: inset 0 1px 3px #ddd; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + vertical-align: middle; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-form input:not([type]) { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + -webkit-box-shadow: inset 0 1px 3px #ddd; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-form input[type="color"] { + padding: 0.2em 0.5em; +} +.pure-form input[type="color"]:focus, +.pure-form input[type="date"]:focus, +.pure-form input[type="datetime-local"]:focus, +.pure-form input[type="datetime"]:focus, +.pure-form input[type="email"]:focus, +.pure-form input[type="month"]:focus, +.pure-form input[type="number"]:focus, +.pure-form input[type="password"]:focus, +.pure-form input[type="search"]:focus, +.pure-form input[type="tel"]:focus, +.pure-form input[type="text"]:focus, +.pure-form input[type="time"]:focus, +.pure-form input[type="url"]:focus, +.pure-form input[type="week"]:focus, +.pure-form select:focus, +.pure-form textarea:focus { + outline: 0; + border-color: #129fea; +} +.pure-form input:not([type]):focus { + outline: 0; + border-color: #129fea; +} +.pure-form input[type="checkbox"]:focus, +.pure-form input[type="file"]:focus, +.pure-form input[type="radio"]:focus { + outline: thin solid #129fea; + outline: 1px auto #129fea; +} +.pure-form .pure-checkbox, +.pure-form .pure-radio { + margin: 0.5em 0; + display: block; +} +.pure-form input[type="color"][disabled], +.pure-form input[type="date"][disabled], +.pure-form input[type="datetime-local"][disabled], +.pure-form input[type="datetime"][disabled], +.pure-form input[type="email"][disabled], +.pure-form input[type="month"][disabled], +.pure-form input[type="number"][disabled], +.pure-form input[type="password"][disabled], +.pure-form input[type="search"][disabled], +.pure-form input[type="tel"][disabled], +.pure-form input[type="text"][disabled], +.pure-form input[type="time"][disabled], +.pure-form input[type="url"][disabled], +.pure-form input[type="week"][disabled], +.pure-form select[disabled], +.pure-form textarea[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} +.pure-form input:not([type])[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} +.pure-form input[readonly], +.pure-form select[readonly], +.pure-form textarea[readonly] { + background-color: #eee; + color: #777; + border-color: #ccc; +} +.pure-form input:focus:invalid, +.pure-form select:focus:invalid, +.pure-form textarea:focus:invalid { + color: #b94a48; + border-color: #e9322d; +} +.pure-form input[type="checkbox"]:focus:invalid:focus, +.pure-form input[type="file"]:focus:invalid:focus, +.pure-form input[type="radio"]:focus:invalid:focus { + outline-color: #e9322d; +} +.pure-form select { + height: 2.25em; + border: 1px solid #ccc; + background-color: #fff; +} +.pure-form select[multiple] { + height: auto; +} +.pure-form label { + margin: 0.5em 0 0.2em; +} +.pure-form fieldset { + margin: 0; + padding: 0.35em 0 0.75em; + border: 0; +} +.pure-form legend { + display: block; + width: 100%; + padding: 0.3em 0; + margin-bottom: 0.3em; + color: #333; + border-bottom: 1px solid #e5e5e5; +} +.pure-form-stacked input[type="color"], +.pure-form-stacked input[type="date"], +.pure-form-stacked input[type="datetime-local"], +.pure-form-stacked input[type="datetime"], +.pure-form-stacked input[type="email"], +.pure-form-stacked input[type="file"], +.pure-form-stacked input[type="month"], +.pure-form-stacked input[type="number"], +.pure-form-stacked input[type="password"], +.pure-form-stacked input[type="search"], +.pure-form-stacked input[type="tel"], +.pure-form-stacked input[type="text"], +.pure-form-stacked input[type="time"], +.pure-form-stacked input[type="url"], +.pure-form-stacked input[type="week"], +.pure-form-stacked label, +.pure-form-stacked select, +.pure-form-stacked textarea { + display: block; + margin: 0.25em 0; +} +.pure-form-stacked input:not([type]) { + display: block; + margin: 0.25em 0; +} +.pure-form-aligned input, +.pure-form-aligned select, +.pure-form-aligned textarea, +.pure-form-message-inline { + display: inline-block; + vertical-align: middle; +} +.pure-form-aligned textarea { + vertical-align: top; +} +.pure-form-aligned .pure-control-group { + margin-bottom: 0.5em; +} +.pure-form-aligned .pure-control-group label { + text-align: right; + display: inline-block; + vertical-align: middle; + width: 10em; + margin: 0 1em 0 0; +} +.pure-form-aligned .pure-controls { + margin: 1.5em 0 0 11em; +} +.pure-form .pure-input-rounded, +.pure-form input.pure-input-rounded { + border-radius: 2em; + padding: 0.5em 1em; +} +.pure-form .pure-group fieldset { + margin-bottom: 10px; +} +.pure-form .pure-group input, +.pure-form .pure-group textarea { + display: block; + padding: 10px; + margin: 0 0 -1px; + border-radius: 0; + position: relative; + top: -1px; +} +.pure-form .pure-group input:focus, +.pure-form .pure-group textarea:focus { + z-index: 3; +} +.pure-form .pure-group input:first-child, +.pure-form .pure-group textarea:first-child { + top: 1px; + border-radius: 4px 4px 0 0; + margin: 0; +} +.pure-form .pure-group input:first-child:last-child, +.pure-form .pure-group textarea:first-child:last-child { + top: 1px; + border-radius: 4px; + margin: 0; +} +.pure-form .pure-group input:last-child, +.pure-form .pure-group textarea:last-child { + top: -2px; + border-radius: 0 0 4px 4px; + margin: 0; +} +.pure-form .pure-group button { + margin: 0.35em 0; +} +.pure-form .pure-input-1 { + width: 100%; +} +.pure-form .pure-input-3-4 { + width: 75%; +} +.pure-form .pure-input-2-3 { + width: 66%; +} +.pure-form .pure-input-1-2 { + width: 50%; +} +.pure-form .pure-input-1-3 { + width: 33%; +} +.pure-form .pure-input-1-4 { + width: 25%; +} +.pure-form-message-inline { + display: inline-block; + padding-left: 0.3em; + color: #666; + vertical-align: middle; + font-size: 0.875em; +} +.pure-form-message { + display: block; + color: #666; + font-size: 0.875em; +} +@media only screen and (max-width: 480px) { + .pure-form button[type="submit"] { + margin: 0.7em 0 0; + } + .pure-form input:not([type]), + .pure-form input[type="color"], + .pure-form input[type="date"], + .pure-form input[type="datetime-local"], + .pure-form input[type="datetime"], + .pure-form input[type="email"], + .pure-form input[type="month"], + .pure-form input[type="number"], + .pure-form input[type="password"], + .pure-form input[type="search"], + .pure-form input[type="tel"], + .pure-form input[type="text"], + .pure-form input[type="time"], + .pure-form input[type="url"], + .pure-form input[type="week"], + .pure-form label { + margin-bottom: 0.3em; + display: block; + } + .pure-group input:not([type]), + .pure-group input[type="color"], + .pure-group input[type="date"], + .pure-group input[type="datetime-local"], + .pure-group input[type="datetime"], + .pure-group input[type="email"], + .pure-group input[type="month"], + .pure-group input[type="number"], + .pure-group input[type="password"], + .pure-group input[type="search"], + .pure-group input[type="tel"], + .pure-group input[type="text"], + .pure-group input[type="time"], + .pure-group input[type="url"], + .pure-group input[type="week"] { + margin-bottom: 0; + } + .pure-form-aligned .pure-control-group label { + margin-bottom: 0.3em; + text-align: left; + display: block; + width: 100%; + } + .pure-form-aligned .pure-controls { + margin: 1.5em 0 0 0; + } + .pure-form-message, + .pure-form-message-inline { + display: block; + font-size: 0.75em; + padding: 0.2em 0 0.8em; + } +} +.pure-menu { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-menu-fixed { + position: fixed; + left: 0; + top: 0; + z-index: 3; +} +.pure-menu-item, +.pure-menu-list { + position: relative; +} +.pure-menu-list { + list-style: none; + margin: 0; + padding: 0; +} +.pure-menu-item { + padding: 0; + margin: 0; + height: 100%; +} +.pure-menu-heading, +.pure-menu-link { + display: block; + text-decoration: none; + white-space: nowrap; +} +.pure-menu-horizontal { + width: 100%; + white-space: nowrap; +} +.pure-menu-horizontal .pure-menu-list { + display: inline-block; +} +.pure-menu-horizontal .pure-menu-heading, +.pure-menu-horizontal .pure-menu-item, +.pure-menu-horizontal .pure-menu-separator { + display: inline-block; + vertical-align: middle; +} +.pure-menu-item .pure-menu-item { + display: block; +} +.pure-menu-children { + display: none; + position: absolute; + left: 100%; + top: 0; + margin: 0; + padding: 0; + z-index: 3; +} +.pure-menu-horizontal .pure-menu-children { + left: 0; + top: auto; + width: inherit; +} +.pure-menu-active > .pure-menu-children, +.pure-menu-allow-hover:hover > .pure-menu-children { + display: block; + position: absolute; +} +.pure-menu-has-children > .pure-menu-link:after { + padding-left: 0.5em; + content: "\25B8"; + font-size: small; +} +.pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after { + content: "\25BE"; +} +.pure-menu-scrollable { + overflow-y: scroll; + overflow-x: hidden; +} +.pure-menu-scrollable .pure-menu-list { + display: block; +} +.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list { + display: inline-block; +} +.pure-menu-horizontal.pure-menu-scrollable { + white-space: nowrap; + overflow-y: hidden; + overflow-x: auto; + padding: 0.5em 0; +} +.pure-menu-horizontal .pure-menu-children .pure-menu-separator, +.pure-menu-separator { + background-color: #ccc; + height: 1px; + margin: 0.3em 0; +} +.pure-menu-horizontal .pure-menu-separator { + width: 1px; + height: 1.3em; + margin: 0 0.3em; +} +.pure-menu-horizontal .pure-menu-children .pure-menu-separator { + display: block; + width: auto; +} +.pure-menu-heading { + text-transform: uppercase; + color: #565d64; +} +.pure-menu-link { + color: #777; +} +.pure-menu-children { + background-color: #fff; +} +.pure-menu-disabled, +.pure-menu-heading, +.pure-menu-link { + padding: 0.5em 1em; +} +.pure-menu-disabled { + opacity: 0.5; +} +.pure-menu-disabled .pure-menu-link:hover { + background-color: transparent; +} +.pure-menu-active > .pure-menu-link, +.pure-menu-link:focus, +.pure-menu-link:hover { + background-color: #eee; +} +.pure-menu-selected > .pure-menu-link, +.pure-menu-selected > .pure-menu-link:visited { + color: #000; +} +.pure-table { + border-collapse: collapse; + border-spacing: 0; + empty-cells: show; + border: 1px solid #cbcbcb; +} +.pure-table caption { + color: #000; + font: italic 85%/1 arial, sans-serif; + padding: 1em 0; + text-align: center; +} +.pure-table td, +.pure-table th { + border-left: 1px solid #cbcbcb; + border-width: 0 0 0 1px; + font-size: inherit; + margin: 0; + overflow: visible; + padding: 0.5em 1em; +} +.pure-table thead { + background-color: #e0e0e0; + color: #000; + text-align: left; + vertical-align: bottom; +} +.pure-table td { + background-color: transparent; +} +.pure-table-odd td { + background-color: #f2f2f2; +} +.pure-table-striped tr:nth-child(2n-1) td { + background-color: #f2f2f2; +} +.pure-table-bordered td { + border-bottom: 1px solid #cbcbcb; +} +.pure-table-bordered tbody > tr:last-child > td { + border-bottom-width: 0; +} +.pure-table-horizontal td, +.pure-table-horizontal th { + border-width: 0 0 1px 0; + border-bottom: 1px solid #cbcbcb; +} +.pure-table-horizontal tbody > tr:last-child > td { + border-bottom-width: 0; +} diff --git a/packages/merchant-backend-ui/src/css/style.css b/packages/merchant-backend-ui/src/css/style.css new file mode 100644 index 000000000..f24dbaa87 --- /dev/null +++ b/packages/merchant-backend-ui/src/css/style.css @@ -0,0 +1,61 @@ +/*! + Pure v2.0.3 + Copyright 2013 Yahoo! + Licensed under the BSD License. + https://github.com/pure-ss/pure/blob/master/LICENSE.md +*/ +/*! + normalize.cs v | MIT License | git.io/normalize + Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.ss v8.0.1 | MIT License | github.com/necolas/normalize.cs */ + +.talerbar { + text-align: center; +} +.tt { + font-family: "Lucida Console", Monaco, monospace; +} +.content { + overflow-x: auto; + padding-left: 15%; + padding-right: 15%; +} +.qr { + margin: auto; + text-align: center; +} +.qrtext { + width: max-content; + margin: auto; + transition: font-size 0.2s; + font-family: "Lucida Console", Monaco, monospace; + font-size: 0.5em; +} +.qrtext:hover { + font-size: 1em; +} +.talerbar { + margin: 0; + bottom: 0; + background-color: #033; + color: white; + width: 100%; + padding: 1em; + overflow: auto; +} +body { + overflow-y: scroll; +} +@media (min-width: 500px) { + .content { + padding-bottom: 2em; + overflow-y: auto; + } +} +#main a:link, +#main a:visited, +#main a:hover, +#main a:active { + color: black; +}
\ No newline at end of file diff --git a/packages/merchant-backend-ui/src/custom.d.ts b/packages/merchant-backend-ui/src/custom.d.ts new file mode 100644 index 000000000..d2705003b --- /dev/null +++ b/packages/merchant-backend-ui/src/custom.d.ts @@ -0,0 +1,40 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +declare module '*.po' { + const content: any; + export default content; +} +declare module 'jed' { + const x: any; + export = x; +} +declare module "*.jpeg" { + const content: any; + export default content; +} +declare module "*.png" { + const content: any; + export default content; +} +declare module '*.svg' { + const content: any; + export default content; +} + +declare module '*.scss' { + const content: Record<string, string>; + export default content; +} diff --git a/packages/merchant-backend-ui/src/declaration.d.ts b/packages/merchant-backend-ui/src/declaration.d.ts new file mode 100644 index 000000000..74b0a5011 --- /dev/null +++ b/packages/merchant-backend-ui/src/declaration.d.ts @@ -0,0 +1,1384 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + + +type HashCode = string; +type EddsaPublicKey = string; +type EddsaSignature = string; +type WireTransferIdentifierRawP = string; +type RelativeTime = Duration; +type ImageDataUrl = string; + +export interface WithId { + id: string +} + +interface Timestamp { + // Milliseconds since epoch, or the special + // value "forever" to represent an event that will + // never happen. + t_s: number | "never"; +} +interface Duration { + // Duration in milliseconds or "forever" + // to represent an infinite duration. + d_us: number | "forever"; +} + +interface WithId { + id: string; +} + +type Amount = string; +type UUID = string; +type Integer = number; + +export namespace ExchangeBackend { + interface WireResponse { + + // Master public key of the exchange, must match the key returned in /keys. + master_public_key: EddsaPublicKey; + + // Array of wire accounts operated by the exchange for + // incoming wire transfers. + accounts: WireAccount[]; + + // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank") + // to wire fees. + fees: { method: AggregateTransferFee }; + } + interface WireAccount { + // payto:// URI identifying the account and wire method + payto_uri: string; + + // Signature using the exchange's offline key + // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS. + master_sig: EddsaSignature; + } + interface AggregateTransferFee { + // Per transfer wire transfer fee. + wire_fee: Amount; + + // Per transfer closing fee. + closing_fee: Amount; + + // What date (inclusive) does this fee go into effect? + // The different fees must cover the full time period in which + // any of the denomination keys are valid without overlap. + start_date: TalerProtocolTimestamp; + + // What date (exclusive) does this fee stop going into effect? + // The different fees must cover the full time period in which + // any of the denomination keys are valid without overlap. + end_date: TalerProtocolTimestamp; + + // Signature of TALER_MasterWireFeePS with + // purpose TALER_SIGNATURE_MASTER_WIRE_FEES. + sig: EddsaSignature; + } + +} +export namespace MerchantBackend { + interface ErrorDetail { + + // Numeric error code unique to the condition. + // The other arguments are specific to the error value reported here. + code: number; + + // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ... + // Should give a human-readable hint about the error's nature. Optional, may change without notice! + hint?: string; + + // Optional detail about the specific input value that failed. May change without notice! + detail?: string; + + // Name of the parameter that was bogus (if applicable). + parameter?: string; + + // Path to the argument that was bogus (if applicable). + path?: string; + + // Offset of the argument that was bogus (if applicable). + offset?: string; + + // Index of the argument that was bogus (if applicable). + index?: string; + + // Name of the object that was bogus (if applicable). + object?: string; + + // Name of the currency than was problematic (if applicable). + currency?: string; + + // Expected type (if applicable). + type_expected?: string; + + // Type that was provided instead (if applicable). + type_actual?: string; + } + + + // Delivery location, loosely modeled as a subset of + // ISO20022's PostalAddress25. + interface Tax { + // the name of the tax + name: string; + + // amount paid in tax + tax: Amount; + } + + interface Auditor { + // official name + name: string; + + // Auditor's public key + auditor_pub: EddsaPublicKey; + + // Base URL of the auditor + url: string; + } + interface Exchange { + // the exchange's base URL + url: string; + + // master public key of the exchange + master_pub: EddsaPublicKey; + } + + interface Product { + // merchant-internal identifier for the product. + product_id?: string; + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n?: { [lang_tag: string]: string }; + + // The number of units of the product to deliver to the customer. + quantity: Integer; + + // The unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price of the product; this is the total price for quantity times unit of this product. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for this product. Can be empty. + taxes: Tax[]; + + // time indicating when this product should be delivered + delivery_date?: Timestamp; + } + interface Merchant { + // label for a location with the business address of the merchant + address: Location; + + // the merchant's legal name of business + name: string; + + // label for a location that denotes the jurisdiction for disputes. + // Some of the typical fields for a location (such as a street address) may be absent. + jurisdiction: Location; + } + + interface VersionResponse { + // libtool-style representation of the Merchant protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Name of the protocol. + name: "taler-merchant"; + + // Currency supported by this backend. + currency: string; + + } + interface Location { + // Nation with its own government. + country?: string; + + // Identifies a subdivision of a country such as state, region, county. + country_subdivision?: string; + + // Identifies a subdivision within a country sub-division. + district?: string; + + // Name of a built-up area, with defined boundaries, and a local government. + town?: string; + + // Specific location name within the town. + town_location?: string; + + // Identifier consisting of a group of letters and/or numbers that + // is added to a postal address to assist the sorting of mail. + post_code?: string; + + // Name of a street or thoroughfare. + street?: string; + + // Name of the building or house. + building_name?: string; + + // Number that identifies the position of a building on a street. + building_number?: string; + + // Free-form address lines, should not exceed 7 elements. + address_lines?: string[]; + } + namespace Instances { + + //POST /private/instances/$INSTANCE/auth + interface InstanceAuthConfigurationMessage { + // Type of authentication. + // "external": The mechant backend does not do + // any authentication checks. Instead an API + // gateway must do the authentication. + // "token": The merchant checks an auth token. + // See "token" for details. + method: "external" | "token"; + + // For method "external", this field is mandatory. + // The token MUST begin with the string "secret-token:". + // After the auth token has been set (with method "token"), + // the value must be provided in a "Authorization: Bearer $token" + // header. + token?: string; + + } + //POST /private/instances + interface InstanceConfigurationMessage { + // The URI where the wallet will send coins. A merchant may have + // multiple accounts, thus this is an array. Note that by + // removing URIs from this list the respective account is set to + // inactive and thus unavailable for new contracts, but preserved + // in the database as existing offers and contracts may still refer + // to it. + payto_uris: string[]; + + // Name of the merchant instance to create (will become $INSTANCE). + id: string; + + // Merchant name corresponding to this instance. + name: string; + + // "Authentication" header required to authorize management access the instance. + // Optional, if not given authentication will be disabled for + // this instance (hopefully authentication checks are still + // done by some reverse proxy). + auth: InstanceAuthConfigurationMessage; + + // The merchant's physical address (to be put into contracts). + address: Location; + + // The jurisdiction under which the merchant conducts its business + // (to be put into contracts). + jurisdiction: Location; + + // Maximum wire fee this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_wire_fee: Amount; + + // Default factor for wire fee amortization calculations. + // Can be overridden by the frontend on a per-order basis. + default_wire_fee_amortization: Integer; + + // Maximum deposit fee (sum over all coins) this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_deposit_fee: Amount; + + // If the frontend does NOT specify an execution date, how long should + // we tell the exchange to wait to aggregate transactions before + // executing the wire transfer? This delay is added to the current + // time when we generate the advisory execution time for the exchange. + default_wire_transfer_delay: RelativeTime; + + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? + default_pay_delay: RelativeTime; + + } + + // PATCH /private/instances/$INSTANCE + interface InstanceReconfigurationMessage { + // The URI where the wallet will send coins. A merchant may have + // multiple accounts, thus this is an array. Note that by + // removing URIs from this list + payto_uris: string[]; + + // Merchant name corresponding to this instance. + name: string; + + // The merchant's physical address (to be put into contracts). + address: Location; + + // The jurisdiction under which the merchant conducts its business + // (to be put into contracts). + jurisdiction: Location; + + // Maximum wire fee this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_wire_fee: Amount; + + // Default factor for wire fee amortization calculations. + // Can be overridden by the frontend on a per-order basis. + default_wire_fee_amortization: Integer; + + // Maximum deposit fee (sum over all coins) this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_deposit_fee: Amount; + + // If the frontend does NOT specify an execution date, how long should + // we tell the exchange to wait to aggregate transactions before + // executing the wire transfer? This delay is added to the current + // time when we generate the advisory execution time for the exchange. + default_wire_transfer_delay: RelativeTime; + + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? + default_pay_delay: RelativeTime; + + } + + // GET /private/instances + interface InstancesResponse { + // List of instances that are present in the backend (see Instance) + instances: Instance[]; + } + + interface Instance { + // Merchant name corresponding to this instance. + name: string; + + deleted?: boolean; + + // Merchant instance this response is about ($INSTANCE) + id: string; + + // Public key of the merchant/instance, in Crockford Base32 encoding. + merchant_pub: EddsaPublicKey; + + // List of the payment targets supported by this instance. Clients can + // specify the desired payment target in /order requests. Note that + // front-ends do not have to support wallets selecting payment targets. + payment_targets: string[]; + + } + + //GET /private/instances/$INSTANCE + interface QueryInstancesResponse { + // The URI where the wallet will send coins. A merchant may have + // multiple accounts, thus this is an array. + accounts: MerchantAccount[]; + + // Merchant name corresponding to this instance. + name: string; + + // Public key of the merchant/instance, in Crockford Base32 encoding. + merchant_pub: EddsaPublicKey; + + // The merchant's physical address (to be put into contracts). + address: Location; + + // The jurisdiction under which the merchant conducts its business + // (to be put into contracts). + jurisdiction: Location; + + // Maximum wire fee this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_wire_fee: Amount; + + // Default factor for wire fee amortization calculations. + // Can be overridden by the frontend on a per-order basis. + default_wire_fee_amortization: Integer; + + // Maximum deposit fee (sum over all coins) this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_deposit_fee: Amount; + + // If the frontend does NOT specify an execution date, how long should + // we tell the exchange to wait to aggregate transactions before + // executing the wire transfer? This delay is added to the current + // time when we generate the advisory execution time for the exchange. + default_wire_transfer_delay: RelativeTime; + + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? + default_pay_delay: RelativeTime; + + // Authentication configuration. + // Does not contain the token when token auth is configured. + auth: { + method: "external" | "token"; + }; + } + + interface MerchantAccount { + + // payto:// URI of the account. + payto_uri: string; + + // Hash over the wire details (including over the salt) + h_wire: HashCode; + + // salt used to compute h_wire + salt: HashCode; + + // true if this account is active, + // false if it is historic. + active: boolean; + } + + // DELETE /private/instances/$INSTANCE + + + } + + namespace Products { + // POST /private/products + interface ProductAddDetail { + + // product ID to use. + product_id: string; + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n: { [lang_tag: string]: string }; + + // unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price for one unit of the product. Zero is used + // to imply that this product is not sold separately, or + // that the price is not fixed, and must be supplied by the + // front-end. If non-zero, this price MUST include applicable + // taxes. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for one unit of this product + taxes: Tax[]; + + // Number of units of the product in stock in sum in total, + // including all existing sales ever. Given in product-specific + // units. + // A value of -1 indicates "infinite" (i.e. for "electronic" books). + total_stock: Integer; + + // Identifies where the product is in stock. + address: Location; + + // Identifies when we expect the next restocking to happen. + next_restock?: Timestamp; + + } + // PATCH /private/products/$PRODUCT_ID + interface ProductPatchDetail { + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n: { [lang_tag: string]: string }; + + // unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price for one unit of the product. Zero is used + // to imply that this product is not sold separately, or + // that the price is not fixed, and must be supplied by the + // front-end. If non-zero, this price MUST include applicable + // taxes. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for one unit of this product + taxes: Tax[]; + + // Number of units of the product in stock in sum in total, + // including all existing sales ever. Given in product-specific + // units. + // A value of -1 indicates "infinite" (i.e. for "electronic" books). + total_stock: Integer; + + // Number of units of the product that were lost (spoiled, stolen, etc.) + total_lost: Integer; + + // Identifies where the product is in stock. + address: Location; + + // Identifies when we expect the next restocking to happen. + next_restock?: Timestamp; + + } + + // GET /private/products + interface InventorySummaryResponse { + // List of products that are present in the inventory + products: InventoryEntry[]; + } + interface InventoryEntry { + // Product identifier, as found in the product. + product_id: string; + + } + + // GET /private/products/$PRODUCT_ID + interface ProductDetail { + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n: { [lang_tag: string]: string }; + + // unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price for one unit of the product. Zero is used + // to imply that this product is not sold separately, or + // that the price is not fixed, and must be supplied by the + // front-end. If non-zero, this price MUST include applicable + // taxes. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for one unit of this product + taxes: Tax[]; + + // Number of units of the product in stock in sum in total, + // including all existing sales ever. Given in product-specific + // units. + // A value of -1 indicates "infinite" (i.e. for "electronic" books). + total_stock: Integer; + + // Number of units of the product that have already been sold. + total_sold: Integer; + + // Number of units of the product that were lost (spoiled, stolen, etc.) + total_lost: Integer; + + // Identifies where the product is in stock. + address: Location; + + // Identifies when we expect the next restocking to happen. + next_restock?: Timestamp; + + } + + // POST /private/products/$PRODUCT_ID/lock + interface LockRequest { + + // UUID that identifies the frontend performing the lock + // It is suggested that clients use a timeflake for this, + // see https://github.com/anthonynsimon/timeflake + lock_uuid: UUID; + + // How long does the frontend intend to hold the lock + duration: RelativeTime; + + // How many units should be locked? + quantity: Integer; + + } + + // DELETE /private/products/$PRODUCT_ID + + } + + namespace Orders { + + type MerchantOrderStatusResponse = CheckPaymentPaidResponse | + CheckPaymentClaimedResponse | + CheckPaymentUnpaidResponse; + interface CheckPaymentPaidResponse { + // The customer paid for this contract. + order_status: "paid"; + + // Was the payment refunded (even partially)? + refunded: boolean; + + // True if there are any approved refunds that the wallet has + // not yet obtained. + refund_pending: boolean; + + // Did the exchange wire us the funds? + wired: boolean; + + // Total amount the exchange deposited into our bank account + // for this contract, excluding fees. + deposit_total: Amount; + + // Numeric error code indicating errors the exchange + // encountered tracking the wire transfer for this purchase (before + // we even got to specific coin issues). + // 0 if there were no issues. + exchange_ec: number; + + // HTTP status code returned by the exchange when we asked for + // information to track the wire transfer for this purchase. + // 0 if there were no issues. + exchange_hc: number; + + // Total amount that was refunded, 0 if refunded is false. + refund_amount: Amount; + + // Contract terms. + contract_terms: ContractTerms; + + // The wire transfer status from the exchange for this order if + // available, otherwise empty array. + wire_details: TransactionWireTransfer[]; + + // Reports about trouble obtaining wire transfer details, + // empty array if no trouble were encountered. + wire_reports: TransactionWireReport[]; + + // The refund details for this order. One entry per + // refunded coin; empty array if there are no refunds. + refund_details: RefundDetails[]; + + // Status URL, can be used as a redirect target for the browser + // to show the order QR code / trigger the wallet. + order_status_url: string; + } + interface CheckPaymentClaimedResponse { + // A wallet claimed the order, but did not yet pay for the contract. + order_status: "claimed"; + + // Contract terms. + contract_terms: ContractTerms; + + } + interface CheckPaymentUnpaidResponse { + // The order was neither claimed nor paid. + order_status: "unpaid"; + + // when was the order created + creation_time: Timestamp; + + // Order summary text. + summary: string; + + // Total amount of the order (to be paid by the customer). + total_amount: Amount; + + // URI that the wallet must process to complete the payment. + taler_pay_uri: string; + + // Alternative order ID which was paid for already in the same session. + // Only given if the same product was purchased before in the same session. + already_paid_order_id?: string; + + // Fulfillment URL of an already paid order. Only given if under this + // session an already paid order with a fulfillment URL exists. + already_paid_fulfillment_url?: string; + + // Status URL, can be used as a redirect target for the browser + // to show the order QR code / trigger the wallet. + order_status_url: string; + + // We do we NOT return the contract terms here because they may not + // exist in case the wallet did not yet claim them. + } + interface RefundDetails { + // Reason given for the refund. + reason: string; + + // When was the refund approved. + timestamp: Timestamp; + + // Total amount that was refunded (minus a refund fee). + amount: Amount; + } + interface TransactionWireTransfer { + // Responsible exchange. + exchange_url: string; + + // 32-byte wire transfer identifier. + wtid: Base32; + + // Execution time of the wire transfer. + execution_time: Timestamp; + + // Total amount that has been wire transferred + // to the merchant. + amount: Amount; + + // Was this transfer confirmed by the merchant via the + // POST /transfers API, or is it merely claimed by the exchange? + confirmed: boolean; + } + interface TransactionWireReport { + // Numerical error code. + code: number; + + // Human-readable error description. + hint: string; + + // Numerical error code from the exchange. + exchange_ec: number; + + // HTTP status code received from the exchange. + exchange_hc: number; + + // Public key of the coin for which we got the exchange error. + coin_pub: CoinPublicKey; + } + + interface OrderHistory { + // timestamp-sorted array of all orders matching the query. + // The order of the sorting depends on the sign of delta. + orders: OrderHistoryEntry[]; + } + interface OrderHistoryEntry { + + // order ID of the transaction related to this entry. + order_id: string; + + // row ID of the order in the database + row_id: number; + + // when the order was created + timestamp: Timestamp; + + // the amount of money the order is for + amount: Amount; + + // the summary of the order + summary: string; + + // whether some part of the order is refundable, + // that is the refund deadline has not yet expired + // and the total amount refunded so far is below + // the value of the original transaction. + refundable: boolean; + + // whether the order has been paid or not + paid: boolean; + } + + interface PostOrderRequest { + // The order must at least contain the minimal + // order detail, but can override all + order: Order; + + // if set, the backend will then set the refund deadline to the current + // time plus the specified delay. If it's not set, refunds will not be + // possible. + refund_delay?: RelativeTime; + + // specifies the payment target preferred by the client. Can be used + // to select among the various (active) wire methods supported by the instance. + payment_target?: string; + + // specifies that some products are to be included in the + // order from the inventory. For these inventory management + // is performed (so the products must be in stock) and + // details are completed from the product data of the backend. + inventory_products?: MinimalInventoryProduct[]; + + // Specifies a lock identifier that was used to + // lock a product in the inventory. Only useful if + // manage_inventory is set. Used in case a frontend + // reserved quantities of the individual products while + // the shopping card was being built. Multiple UUIDs can + // be used in case different UUIDs were used for different + // products (i.e. in case the user started with multiple + // shopping sessions that were combined during checkout). + lock_uuids?: UUID[]; + + // Should a token for claiming the order be generated? + // False can make sense if the ORDER_ID is sufficiently + // high entropy to prevent adversarial claims (like it is + // if the backend auto-generates one). Default is 'true'. + create_token?: boolean; + + } + type Order = MinimalOrderDetail | ContractTerms; + + interface MinimalOrderDetail { + // Amount to be paid by the customer + amount: Amount; + + // Short summary of the order + summary: string; + + // URL that will show that the order was successful after + // it has been paid for. Optional. When POSTing to the + // merchant, the placeholder "${ORDER_ID}" will be + // replaced with the actual order ID (useful if the + // order ID is generated server-side and needs to be + // in the URL). + fulfillment_url?: string; + } + + interface MinimalInventoryProduct { + // Which product is requested (here mandatory!) + product_id: string; + + // How many units of the product are requested + quantity: Integer; + } + interface PostOrderResponse { + // Order ID of the response that was just created + order_id: string; + + // Token that authorizes the wallet to claim the order. + // Provided only if "create_token" was set to 'true' + // in the request. + token?: ClaimToken; + } + interface OutOfStockResponse { + + // Product ID of an out-of-stock item + product_id: string; + + // Requested quantity + requested_quantity: Integer; + + // Available quantity (must be below requested_quanitity) + available_quantity: Integer; + + // When do we expect the product to be again in stock? + // Optional, not given if unknown. + restock_expected?: Timestamp; + } + + interface ForgetRequest { + + // Array of valid JSON paths to forgettable fields in the order's + // contract terms. + fields: string[]; + } + interface RefundRequest { + // Amount to be refunded + refund: Amount; + + // Human-readable refund justification + reason: string; + } + interface MerchantRefundResponse { + + // URL (handled by the backend) that the wallet should access to + // trigger refund processing. + // taler://refund/... + taler_refund_uri: string; + + // Contract hash that a client may need to authenticate an + // HTTP request to obtain the above URI in a wallet-friendly way. + h_contract: HashCode; + } + + } + + namespace Tips { + + // GET /private/reserves + interface TippingReserveStatus { + // Array of all known reserves (possibly empty!) + reserves: ReserveStatusEntry[]; + } + interface ReserveStatusEntry { + // Public key of the reserve + reserve_pub: EddsaPublicKey; + + // Timestamp when it was established + creation_time: Timestamp; + + // Timestamp when it expires + expiration_time: Timestamp; + + // Initial amount as per reserve creation call + merchant_initial_amount: Amount; + + // Initial amount as per exchange, 0 if exchange did + // not confirm reserve creation yet. + exchange_initial_amount: Amount; + + // Amount picked up so far. + pickup_amount: Amount; + + // Amount approved for tips that exceeds the pickup_amount. + committed_amount: Amount; + + // Is this reserve active (false if it was deleted but not purged) + active: boolean; + } + + interface ReserveCreateRequest { + // Amount that the merchant promises to put into the reserve + initial_balance: Amount; + + // Exchange the merchant intends to use for tipping + exchange_url: string; + + // Desired wire method, for example "iban" or "x-taler-bank" + wire_method: string; + } + interface ReserveCreateConfirmation { + // Public key identifying the reserve + reserve_pub: EddsaPublicKey; + + // Wire account of the exchange where to transfer the funds + payto_uri: string; + } + interface TipCreateRequest { + // Amount that the customer should be tipped + amount: Amount; + + // Justification for giving the tip + justification: string; + + // URL that the user should be directed to after tipping, + // will be included in the tip_token. + next_url: string; + } + interface TipCreateConfirmation { + // Unique tip identifier for the tip that was created. + tip_id: HashCode; + + // taler://tip URI for the tip + taler_tip_uri: string; + + // URL that will directly trigger processing + // the tip when the browser is redirected to it + tip_status_url: string; + + // when does the tip expire + tip_expiration: Timestamp; + } + + interface ReserveDetail { + // Timestamp when it was established. + creation_time: Timestamp; + + // Timestamp when it expires. + expiration_time: Timestamp; + + // Initial amount as per reserve creation call. + merchant_initial_amount: Amount; + + // Initial amount as per exchange, 0 if exchange did + // not confirm reserve creation yet. + exchange_initial_amount: Amount; + + // Amount picked up so far. + pickup_amount: Amount; + + // Amount approved for tips that exceeds the pickup_amount. + committed_amount: Amount; + + // Array of all tips created by this reserves (possibly empty!). + // Only present if asked for explicitly. + tips?: TipStatusEntry[]; + + // Is this reserve active (false if it was deleted but not purged)? + active: boolean; + + // URI to use to fill the reserve, can be NULL + // if the reserve is inactive or was already filled + payto_uri: string; + + // URL of the exchange hosting the reserve, + // NULL if the reserve is inactive + exchange_url: string; + + } + + interface TipStatusEntry { + + // Unique identifier for the tip. + tip_id: HashCode; + + // Total amount of the tip that can be withdrawn. + total_amount: Amount; + + // Human-readable reason for why the tip was granted. + reason: string; + } + + interface TipDetails { + // Amount that we authorized for this tip. + total_authorized: Amount; + + // Amount that was picked up by the user already. + total_picked_up: Amount; + + // Human-readable reason given when authorizing the tip. + reason: string; + + // Timestamp indicating when the tip is set to expire (may be in the past). + expiration: TalerProtocolTimestamp; + + // Reserve public key from which the tip is funded. + reserve_pub: EddsaPublicKey; + + // Array showing the pickup operations of the wallet (possibly empty!). + // Only present if asked for explicitly. + pickups?: PickupDetail[]; + } + interface PickupDetail { + // Unique identifier for the pickup operation. + pickup_id: HashCode; + + // Number of planchets involved. + num_planchets: Integer; + + // Total amount requested for this pickup_id. + requested_amount: Amount; + } + + } + + namespace Transfers { + + interface TransferList { + // list of all the transfers that fit the filter that we know + transfers: TransferDetails[]; + } + interface TransferDetails { + // how much was wired to the merchant (minus fees) + credit_amount: Amount; + + // raw wire transfer identifier identifying the wire transfer (a base32-encoded value) + wtid: string; + + // target account that received the wire transfer + payto_uri: string; + + // base URL of the exchange that made the wire transfer + exchange_url: string; + + // Serial number identifying the transfer in the merchant backend. + // Used for filgering via offset. + transfer_serial_id: number; + + // Time of the execution of the wire transfer by the exchange, according to the exchange + // Only provided if we did get an answer from the exchange. + execution_time?: Timestamp; + + // True if we checked the exchange's answer and are happy with it. + // False if we have an answer and are unhappy, missing if we + // do not have an answer from the exchange. + verified?: boolean; + + // True if the merchant uses the POST /transfers API to confirm + // that this wire transfer took place (and it is thus not + // something merely claimed by the exchange). + confirmed?: boolean; + } + + interface TransferInformation { + // how much was wired to the merchant (minus fees) + credit_amount: Amount; + + // raw wire transfer identifier identifying the wire transfer (a base32-encoded value) + wtid: WireTransferIdentifierRawP; + + // target account that received the wire transfer + payto_uri: string; + + // base URL of the exchange that made the wire transfer + exchange_url: string; + } + interface MerchantTrackTransferResponse { + // Total amount transferred + total: Amount; + + // Applicable wire fee that was charged + wire_fee: Amount; + + // Time of the execution of the wire transfer by the exchange, according to the exchange + execution_time: Timestamp; + + // details about the deposits + deposits_sums: MerchantTrackTransferDetail[]; + } + interface MerchantTrackTransferDetail { + // Business activity associated with the wire transferred amount + // deposit_value. + order_id: string; + + // The total amount the exchange paid back for order_id. + deposit_value: Amount; + + // applicable fees for the deposit + deposit_fee: Amount; + } + + type ExchangeConflictDetails = WireFeeConflictDetails | TrackTransferConflictDetails + // Note: this is not the full 'proof' of missbehavior, as + // the bogus message from the exchange with a signature + // over the 'different' wire fee is missing. + // + // This information is NOT provided by the current implementation, + // because this would be quite expensive to generate and is + // hardly needed _here_. Once we add automated reports for + // the Taler auditor, we need to generate this data anyway + // and should probably return it here as well. + interface WireFeeConflictDetails { + // Numerical error code: + code: "TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_BAD_WIRE_FEE"; + + // Text describing the issue for humans. + hint: string; + + + // Wire fee (wrongly) charged by the exchange, breaking the + // contract affirmed by the exchange_sig. + wire_fee: Amount; + + // Timestamp of the wire transfer + execution_time: Timestamp; + + // The expected wire fee (as signed by the exchange) + expected_wire_fee: Amount; + + // Expected closing fee (needed to verify signature) + expected_closing_fee: Amount; + + // Start date of the expected fee structure + start_date: Timestamp; + + // End date of the expected fee structure + end_date: Timestamp; + + // Signature of the exchange affirming the expected fee structure + master_sig: EddsaSignature; + + // Master public key of the exchange + master_pub: EddsaPublicKey; + } + interface TrackTransferConflictDetails { + // Numerical error code + code: "TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_REPORTS"; + + // Text describing the issue for humans. + hint: string; + + // Offset in the exchange_transfer where the + // exchange's response fails to match the exchange_deposit_proof. + conflict_offset: number; + + // The response from the exchange which tells us when the + // coin was returned to us, except that it does not match + // the expected value of the coin. + // + // This field is NOT provided by the current implementation, + // because this would be quite expensive to generate and is + // hardly needed _here_. Once we add automated reports for + // the Taler auditor, we need to generate this data anyway + // and should probably return it here as well. + // exchange_transfer?: TrackTransferResponse; + + // Public key of the exchange used to sign the response to + // our deposit request. + deposit_exchange_pub: EddsaPublicKey; + + // Signature of the exchange signing the (conflicting) response. + // Signs over a struct TALER_DepositConfirmationPS. + deposit_exchange_sig: EddsaSignature; + + // Hash of the merchant's bank account the wire transfer went to + h_wire: HashCode; + + // Hash of the contract terms with the conflicting deposit. + h_contract_terms: HashCode; + + // At what time the exchange received the deposit. Needed + // to verify the \exchange_sig\. + deposit_timestamp: Timestamp; + + // At what time the refund possibility expired (needed to verify exchange_sig). + refund_deadline: Timestamp; + + // Public key of the coin for which we have conflicting information. + coin_pub: EddsaPublicKey; + + // Amount the exchange counted the coin for in the transfer. + amount_with_fee: Amount; + + // Expected value of the coin. + coin_value: Amount; + + // Expected deposit fee of the coin. + coin_fee: Amount; + + // Expected deposit fee of the coin. + deposit_fee: Amount; + + } + + // interface TrackTransferProof { + // // signature from the exchange made with purpose + // // TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT + // exchange_sig: EddsaSignature; + + // // public EdDSA key of the exchange that was used to generate the signature. + // // Should match one of the exchange's signing keys from /keys. Again given + // // explicitly as the client might otherwise be confused by clock skew as to + // // which signing key was used. + // exchange_pub: EddsaSignature; + + // // hash of the wire details (identical for all deposits) + // // Needed to check the exchange_sig + // h_wire: HashCode; + // } + + } + + + interface ContractTerms { + // Human-readable description of the whole purchase + summary: string; + + // Map from IETF BCP 47 language tags to localized summaries + summary_i18n?: { [lang_tag: string]: string }; + + // Unique, free-form identifier for the proposal. + // Must be unique within a merchant instance. + // For merchants that do not store proposals in their DB + // before the customer paid for them, the order_id can be used + // by the frontend to restore a proposal from the information + // encoded in it (such as a short product identifier and timestamp). + order_id: string; + + // Total price for the transaction. + // The exchange will subtract deposit fees from that amount + // before transferring it to the merchant. + amount: Amount; + + // The URL for this purchase. Every time is is visited, the merchant + // will send back to the customer the same proposal. Clearly, this URL + // can be bookmarked and shared by users. + fulfillment_url?: string; + + // Maximum total deposit fee accepted by the merchant for this contract + max_fee: Amount; + + // Maximum wire fee accepted by the merchant (customer share to be + // divided by the 'wire_fee_amortization' factor, and further reduced + // if deposit fees are below 'max_fee'). Default if missing is zero. + max_wire_fee: Amount; + + // Over how many customer transactions does the merchant expect to + // amortize wire fees on average? If the exchange's wire fee is + // above 'max_wire_fee', the difference is divided by this number + // to compute the expected customer's contribution to the wire fee. + // The customer's contribution may further be reduced by the difference + // between the 'max_fee' and the sum of the actual deposit fees. + // Optional, default value if missing is 1. 0 and negative values are + // invalid and also interpreted as 1. + wire_fee_amortization: number; + + // List of products that are part of the purchase (see Product). + products: Product[]; + + // Time when this contract was generated + timestamp: TalerProtocolTimestamp; + + // After this deadline has passed, no refunds will be accepted. + refund_deadline: TalerProtocolTimestamp; + + // After this deadline, the merchant won't accept payments for the contact + pay_deadline: TalerProtocolTimestamp; + + // Transfer deadline for the exchange. Must be in the + // deposit permissions of coins used to pay for this order. + wire_transfer_deadline: TalerProtocolTimestamp; + + // Merchant's public key used to sign this proposal; this information + // is typically added by the backend Note that this can be an ephemeral key. + merchant_pub: EddsaPublicKey; + + // Base URL of the (public!) merchant backend API. + // Must be an absolute URL that ends with a slash. + merchant_base_url: string; + + // More info about the merchant, see below + merchant: Merchant; + + // The hash of the merchant instance's wire details. + h_wire: HashCode; + + // Wire transfer method identifier for the wire method associated with h_wire. + // The wallet may only select exchanges via a matching auditor if the + // exchange also supports this wire method. + // The wire transfer fees must be added based on this wire transfer method. + wire_method: string; + + // Any exchanges audited by these auditors are accepted by the merchant. + auditors: Auditor[]; + + // Exchanges that the merchant accepts even if it does not accept any auditors that audit them. + exchanges: Exchange[]; + + // Delivery location for (all!) products. + delivery_location?: Location; + + // Time indicating when the order should be delivered. + // May be overwritten by individual products. + delivery_date?: TalerProtocolTimestamp; + + // Nonce generated by the wallet and echoed by the merchant + // in this field when the proposal is generated. + nonce: string; + + // Specifies for how long the wallet should try to get an + // automatic refund for the purchase. If this field is + // present, the wallet should wait for a few seconds after + // the purchase and then automatically attempt to obtain + // a refund. The wallet should probe until "delay" + // after the payment was successful (i.e. via long polling + // or via explicit requests with exponential back-off). + // + // In particular, if the wallet is offline + // at that time, it MUST repeat the request until it gets + // one response from the merchant after the delay has expired. + // If the refund is granted, the wallet MUST automatically + // recover the payment. This is used in case a merchant + // knows that it might be unable to satisfy the contract and + // desires for the wallet to attempt to get the refund without any + // customer interaction. Note that it is NOT an error if the + // merchant does not grant a refund. + auto_refund?: RelativeTime; + + // Extra data that is only interpreted by the merchant frontend. + // Useful when the merchant needs to store extra information on a + // contract without storing it separately in their database. + extra?: any; + } + +} diff --git a/packages/merchant-backend-ui/src/hooks/async.ts b/packages/merchant-backend-ui/src/hooks/async.ts new file mode 100644 index 000000000..fd550043b --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/async.ts @@ -0,0 +1,76 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import { useState } from "preact/hooks"; +import { cancelPendingRequest } from "./backend"; + +export interface Options { + slowTolerance: number, +} + +export interface AsyncOperationApi<T> { + request: (...a: any) => void, + cancel: () => void, + data: T | undefined, + isSlow: boolean, + isLoading: boolean, + error: string | undefined +} + +export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance: tooLong }: Options = { slowTolerance: 1000 }): AsyncOperationApi<T> { + const [data, setData] = useState<T | undefined>(undefined); + const [isLoading, setLoading] = useState<boolean>(false); + const [error, setError] = useState<any>(undefined); + const [isSlow, setSlow] = useState(false) + + const request = async (...args: any) => { + if (!fn) return; + setLoading(true); + + const handler = setTimeout(() => { + setSlow(true) + }, tooLong) + + try { + const result = await fn(...args); + setData(result); + } catch (error) { + setError(error); + } + setLoading(false); + setSlow(false) + clearTimeout(handler) + }; + + function cancel() { + cancelPendingRequest() + setLoading(false); + setSlow(false) + } + + return { + request, + cancel, + data, + isSlow, + isLoading, + error + }; +} diff --git a/packages/merchant-backend-ui/src/hooks/backend.ts b/packages/merchant-backend-ui/src/hooks/backend.ts new file mode 100644 index 000000000..96b8f7139 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/backend.ts @@ -0,0 +1,262 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { mutate, cache } from 'swr'; +import axios, { AxiosError, AxiosResponse } from 'axios' +import { MerchantBackend } from '../declaration'; +import { useBackendContext } from '../context/backend'; +import { useEffect, useState } from 'preact/hooks'; +import { DEFAULT_REQUEST_TIMEOUT } from '../utils/constants'; + +export function mutateAll(re: RegExp, value?: unknown): Array<Promise<any>> { + return cache.keys().filter(key => { + return re.test(key) + }).map(key => { + return mutate(key, value) + }) +} + +export type HttpResponse<T> = HttpResponseOk<T> | HttpResponseLoading<T> | HttpError; +export type HttpResponsePaginated<T> = HttpResponseOkPaginated<T> | HttpResponseLoading<T> | HttpError; + +export interface RequestInfo { + url: string; + hasToken: boolean; + params: unknown; + data: unknown; +} + +interface HttpResponseLoading<T> { + ok?: false; + loading: true; + clientError?: false; + serverError?: false; + + data?: T; +} +export interface HttpResponseOk<T> { + ok: true; + loading?: false; + clientError?: false; + serverError?: false; + + data: T; + info?: RequestInfo; +} + +export type HttpResponseOkPaginated<T> = HttpResponseOk<T> & WithPagination + +export interface WithPagination { + loadMore: () => void; + loadMorePrev: () => void; + isReachingEnd?: boolean; + isReachingStart?: boolean; +} + +export type HttpError = HttpResponseClientError | HttpResponseServerError | HttpResponseUnexpectedError; +export interface SwrError { + info: unknown, + status: number, + message: string, +} +export interface HttpResponseServerError { + ok?: false; + loading?: false; + clientError?: false; + serverError: true; + + error?: MerchantBackend.ErrorDetail; + status: number; + message: string; + info?: RequestInfo; +} +interface HttpResponseClientError { + ok?: false; + loading?: false; + clientError: true; + serverError?: false; + + info?: RequestInfo; + isUnauthorized: boolean; + isNotfound: boolean; + status: number; + error?: MerchantBackend.ErrorDetail; + message: string; + +} + +interface HttpResponseUnexpectedError { + ok?: false; + loading?: false; + clientError?: false; + serverError?: false; + + info?: RequestInfo; + status?: number; + error: unknown; + message: string; +} + +type Methods = 'get' | 'post' | 'patch' | 'delete' | 'put'; + +interface RequestOptions { + method?: Methods; + token?: string; + data?: unknown; + params?: unknown; +} + +function buildRequestOk<T>(res: AxiosResponse<T>, url: string, hasToken: boolean): HttpResponseOk<T> { + return { + ok: true, data: res.data, info: { + params: res.config.params, + data: res.config.data, + url, + hasToken, + } + } +} + +// function buildResponse<T>(data?: T, error?: MerchantBackend.ErrorDetail, isValidating?: boolean): HttpResponse<T> { +// if (isValidating) return {loading: true} +// if (error) return buildRequestFailed() +// } + +function buildRequestFailed(ex: AxiosError<MerchantBackend.ErrorDetail>, url: string, hasToken: boolean): HttpResponseClientError | HttpResponseServerError | HttpResponseUnexpectedError { + const status = ex.response?.status + + const info: RequestInfo = { + data: ex.request?.data, + params: ex.request?.params, + url, + hasToken, + }; + + if (status && status >= 400 && status < 500) { + const error: HttpResponseClientError = { + clientError: true, + isNotfound: status === 404, + isUnauthorized: status === 401, + status, + info, + message: ex.response?.data?.hint || ex.message, + error: ex.response?.data + } + return error + } + if (status && status >= 500 && status < 600) { + const error: HttpResponseServerError = { + serverError: true, + status, + info, + message: `${ex.response?.data?.hint} (code ${ex.response?.data?.code})` || ex.message, + error: ex.response?.data + } + return error; + } + + const error: HttpResponseUnexpectedError = { + info, + status, + error: ex, + message: ex.message + } + + return error +} + + +const CancelToken = axios.CancelToken; +let source = CancelToken.source(); + +export function cancelPendingRequest() { + source.cancel('canceled by the user') + source = CancelToken.source() +} + +let removeAxiosCancelToken = false +/** + * Jest mocking seems to break when using the cancelToken property. + * Using this workaround when testing while finding the correct solution + */ +export function setAxiosRequestAsTestingEnvironment() { + removeAxiosCancelToken = true +} + +export async function request<T>(url: string, options: RequestOptions = {}): Promise<HttpResponseOk<T>> { + const headers = options.token ? { Authorization: `Bearer ${options.token}` } : undefined + + try { + const res = await axios({ + url, + responseType: 'json', + headers, + cancelToken: !removeAxiosCancelToken? source.token : undefined, + method: options.method || 'get', + data: options.data, + params: options.params, + timeout: DEFAULT_REQUEST_TIMEOUT * 1000, + }) + return buildRequestOk<T>(res, url, !!options.token) + } catch (e) { + const error = buildRequestFailed(e, url, !!options.token) + throw error + } + +} + +export function fetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { + return request<T>(`${backend}${url}`, { token }) +} + +export function useBackendInstancesTestForAdmin(): HttpResponse<MerchantBackend.Instances.InstancesResponse> { + const { url, token } = useBackendContext() + + type Type = MerchantBackend.Instances.InstancesResponse; + + const [result, setResult] = useState<HttpResponse<Type>>({ loading: true }) + + useEffect(() => { + request<Type>(`${url}/management/instances`, { token }) + .then(data => setResult(data)) + .catch(error => setResult(error)) + }, [url, token]) + + + return result +} + + +export function useBackendConfig(): HttpResponse<MerchantBackend.VersionResponse> { + const { url, token } = useBackendContext() + + type Type = MerchantBackend.VersionResponse; + + const [result, setResult] = useState<HttpResponse<Type>>({ loading: true }) + + useEffect(() => { + request<Type>(`${url}/config`, { token }) + .then(data => setResult(data)) + .catch(error => setResult(error)) + }, [url, token]) + + return result +} diff --git a/packages/merchant-backend-ui/src/hooks/index.ts b/packages/merchant-backend-ui/src/hooks/index.ts new file mode 100644 index 000000000..19d672ad3 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/index.ts @@ -0,0 +1,110 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { StateUpdater, useCallback, useState } from "preact/hooks"; +import { ValueOrFunction } from '../utils/types'; + + +const calculateRootPath = () => { + const rootPath = typeof window !== undefined ? window.location.origin + window.location.pathname : '/' + return rootPath +} + +export function useBackendURL(url?: string): [string, boolean, StateUpdater<string>, () => void] { + const [value, setter] = useNotNullLocalStorage('backend-url', url || calculateRootPath()) + const [triedToLog, setTriedToLog] = useLocalStorage('tried-login') + + const checkedSetter = (v: ValueOrFunction<string>) => { + setTriedToLog('yes') + return setter(p => (v instanceof Function ? v(p) : v).replace(/\/$/, '')) + } + + const resetBackend = () => { + setTriedToLog(undefined) + } + return [value, !!triedToLog, checkedSetter, resetBackend] +} + +export function useBackendDefaultToken(): [string | undefined, StateUpdater<string | undefined>] { + return useLocalStorage('backend-token') +} + +export function useBackendInstanceToken(id: string): [string | undefined, StateUpdater<string | undefined>] { + const [token, setToken] = useLocalStorage(`backend-token-${id}`) + const [defaultToken, defaultSetToken] = useBackendDefaultToken() + + // instance named 'default' use the default token + if (id === 'default') { + return [defaultToken, defaultSetToken] + } + + return [token, setToken] +} + +export function useLang(initial?: string): [string, StateUpdater<string>] { + const browserLang = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined; + const defaultLang = (browserLang || initial || 'en').substring(0, 2) + return useNotNullLocalStorage('lang-preference', defaultLang) +} + +export function useLocalStorage(key: string, initialValue?: string): [string | undefined, StateUpdater<string | undefined>] { + const [storedValue, setStoredValue] = useState<string | undefined>((): string | undefined => { + return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue; + }); + + const setValue = (value?: string | ((val?: string) => string | undefined)) => { + setStoredValue(p => { + const toStore = value instanceof Function ? value(p) : value + if (typeof window !== "undefined") { + if (!toStore) { + window.localStorage.removeItem(key) + } else { + window.localStorage.setItem(key, toStore); + } + } + return toStore + }) + }; + + return [storedValue, setValue]; +} + +export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] { + const [storedValue, setStoredValue] = useState<string>((): string => { + return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue; + }); + + const setValue = (value: string | ((val: string) => string)) => { + const valueToStore = value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + if (typeof window !== "undefined") { + if (!valueToStore) { + window.localStorage.removeItem(key) + } else { + window.localStorage.setItem(key, valueToStore); + } + } + }; + + return [storedValue, setValue]; +} + + diff --git a/packages/merchant-backend-ui/src/hooks/instance.ts b/packages/merchant-backend-ui/src/hooks/instance.ts new file mode 100644 index 000000000..14ab8de9c --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/instance.ts @@ -0,0 +1,187 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { MerchantBackend } from '../declaration'; +import { useBackendContext } from '../context/backend'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, request, SwrError } from './backend'; +import useSWR, { mutate } from 'swr'; +import { useInstanceContext } from '../context/instance'; + + +interface InstanceAPI { + updateInstance: (data: MerchantBackend.Instances.InstanceReconfigurationMessage) => Promise<void>; + deleteInstance: () => Promise<void>; + clearToken: () => Promise<void>; + setNewToken: (token: string) => Promise<void>; +} + +export function useManagementAPI(instanceId: string) : InstanceAPI { + const { url, token } = useBackendContext() + + const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + await request(`${url}/management/instances/${instanceId}`, { + method: 'patch', + token, + data: instance + }) + + mutate([`/private/`, token, url], null) + }; + + const deleteInstance = async (): Promise<void> => { + await request(`${url}/management/instances/${instanceId}`, { + method: 'delete', + token, + }) + + mutate([`/private/`, token, url], null) + } + + const clearToken = async (): Promise<void> => { + await request(`${url}/management/instances/${instanceId}/auth`, { + method: 'post', + token, + data: { method: 'external' } + }) + + mutate([`/private/`, token, url], null) + } + + const setNewToken = async (newToken: string): Promise<void> => { + await request(`${url}/management/instances/${instanceId}/auth`, { + method: 'post', + token, + data: { method: 'token', token: newToken } + }) + + mutate([`/private/`, token, url], null) + } + + return { updateInstance, deleteInstance, setNewToken, clearToken } +} + +export function useInstanceAPI(): InstanceAPI { + const { url: baseUrl, token: adminToken } = useBackendContext() + const { token: instanceToken, id, admin } = useInstanceContext() + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + await request(`${url}/private/`, { + method: 'patch', + token, + data: instance + }) + + if (adminToken) mutate(['/private/instances', adminToken, baseUrl], null) + mutate([`/private/`, token, url], null) + }; + + const deleteInstance = async (): Promise<void> => { + await request(`${url}/private/`, { + method: 'delete', + token: adminToken, + }) + + if (adminToken) mutate(['/private/instances', adminToken, baseUrl], null) + mutate([`/private/`, token, url], null) + } + + const clearToken = async (): Promise<void> => { + await request(`${url}/private/auth`, { + method: 'post', + token, + data: { method: 'external' } + }) + + mutate([`/private/`, token, url], null) + } + + const setNewToken = async (newToken: string): Promise<void> => { + await request(`${url}/private/auth`, { + method: 'post', + token, + data: { method: 'token', token: newToken } + }) + + mutate([`/private/`, token, url], null) + } + + return { updateInstance, deleteInstance, setNewToken, clearToken } +} + + +export function useInstanceDetails(): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.QueryInstancesResponse>, HttpError>([`/private/`, token, url], fetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + }) + + if (isValidating) return {loading:true, data: data?.data} + if (data) return data + if (error) return error + return {loading: true} +} + +export function useManagedInstanceDetails(instanceId: string): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> { + const { url, token } = useBackendContext(); + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.QueryInstancesResponse>, HttpError>([`/management/instances/${instanceId}`, token, url], fetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + }) + + if (isValidating) return {loading:true, data: data?.data} + if (data) return data + if (error) return error + return {loading: true} +} + +export function useBackendInstances(): HttpResponse<MerchantBackend.Instances.InstancesResponse> { + const { url } = useBackendContext() + const { token } = useInstanceContext(); + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.InstancesResponse>, HttpError>(['/management/instances', token, url], fetcher) + + if (isValidating) return {loading:true, data: data?.data} + if (data) return data + if (error) return error + return {loading: true} +} diff --git a/packages/merchant-backend-ui/src/hooks/listener.ts b/packages/merchant-backend-ui/src/hooks/listener.ts new file mode 100644 index 000000000..231ed6c87 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/listener.ts @@ -0,0 +1,68 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { useState } from "preact/hooks"; + +/** + * returns subscriber and activator + * subscriber will receive a method (listener) that will be call when the activator runs. + * the result of calling the listener will be sent to @action + * + * @param action from <T> to <R> + * @returns activator and subscriber, undefined activator means that there is not subscriber + */ + +export function useListener<T, R = any>(action: (r: T) => Promise<R>): [undefined | (() => Promise<R>), (listener?: () => T) => void] { + type RunnerHandler = { toBeRan?: () => Promise<R>; }; + const [state, setState] = useState<RunnerHandler>({}); + + /** + * subscriber will receive a method that will be call when the activator runs + * + * @param listener function to be run when the activator runs + */ + const subscriber = (listener?: () => T) => { + if (listener) { + setState({ + toBeRan: () => { + const whatWeGetFromTheListener = listener(); + return action(whatWeGetFromTheListener); + } + }); + } else { + setState({ + toBeRan: undefined + }) + } + }; + + /** + * activator will call runner if there is someone subscribed + */ + const activator = state.toBeRan ? async () => { + if (state.toBeRan) { + return state.toBeRan(); + } + return Promise.reject(); + } : undefined; + + return [activator, subscriber]; +} diff --git a/packages/merchant-backend-ui/src/hooks/notification.ts b/packages/merchant-backend-ui/src/hooks/notification.ts new file mode 100644 index 000000000..d1dfbff2c --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/notification.ts @@ -0,0 +1,43 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { useCallback, useState } from "preact/hooks"; +import { Notification } from '../utils/types'; + +interface Result { + notification?: Notification; + pushNotification: (n: Notification) => void; + removeNotification: () => void; +} + +export function useNotification(): Result { + const [notification, setNotifications] = useState<Notification|undefined>(undefined) + + const pushNotification = useCallback((n: Notification): void => { + setNotifications(n) + },[]) + + const removeNotification = useCallback(() => { + setNotifications(undefined) + },[]) + + return { notification, pushNotification, removeNotification } +} diff --git a/packages/merchant-backend-ui/src/hooks/notifications.ts b/packages/merchant-backend-ui/src/hooks/notifications.ts new file mode 100644 index 000000000..1c0c37308 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/notifications.ts @@ -0,0 +1,48 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { useState } from "preact/hooks"; +import { Notification } from '../utils/types'; + +interface Result { + notifications: Notification[]; + pushNotification: (n: Notification) => void; + removeNotification: (n: Notification) => void; +} + +type NotificationWithDate = Notification & { since: Date } + +export function useNotifications(initial: Notification[] = [], timeout = 3000): Result { + const [notifications, setNotifications] = useState<(NotificationWithDate)[]>(initial.map(i => ({...i, since: new Date() }))) + + const pushNotification = (n: Notification): void => { + const entry = { ...n, since: new Date() } + setNotifications(ns => [...ns, entry]) + if (n.type !== 'ERROR') setTimeout(() => { + setNotifications(ns => ns.filter(x => x.since !== entry.since)) + }, timeout) + } + + const removeNotification = (notif: Notification) => { + setNotifications((ns: NotificationWithDate[]) => ns.filter(n => n !== notif)) + } + return { notifications, pushNotification, removeNotification } +} diff --git a/packages/merchant-backend-ui/src/hooks/order.ts b/packages/merchant-backend-ui/src/hooks/order.ts new file mode 100644 index 000000000..4a17eac30 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/order.ts @@ -0,0 +1,217 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { useEffect, useState } from 'preact/hooks'; +import useSWR from 'swr'; +import { useBackendContext } from '../context/backend'; +import { useInstanceContext } from '../context/instance'; +import { MerchantBackend } from '../declaration'; +import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, HttpResponsePaginated, mutateAll, request } from './backend'; + +export interface OrderAPI { + //FIXME: add OutOfStockResponse on 410 + createOrder: (data: MerchantBackend.Orders.PostOrderRequest) => Promise<HttpResponseOk<MerchantBackend.Orders.PostOrderResponse>>; + forgetOrder: (id: string, data: MerchantBackend.Orders.ForgetRequest) => Promise<HttpResponseOk<void>>; + refundOrder: (id: string, data: MerchantBackend.Orders.RefundRequest) => Promise<HttpResponseOk<MerchantBackend.Orders.MerchantRefundResponse>>; + deleteOrder: (id: string) => Promise<HttpResponseOk<void>>; + getPaymentURL: (id: string) => Promise<HttpResponseOk<string>>; +} + +type YesOrNo = 'yes' | 'no'; + + +export function orderFetcher<T>(url: string, token: string, backend: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, searchDate?: Date, delta?: number): Promise<HttpResponseOk<T>> { + const date_ms = delta && delta < 0 && searchDate ? searchDate.getTime() + 1 : searchDate?.getTime() + const params: any = {} + if (paid !== undefined) params.paid = paid + if (delta !== undefined) params.delta = delta + if (refunded !== undefined) params.refunded = refunded + if (wired !== undefined) params.wired = wired + if (date_ms !== undefined) params.date_ms = date_ms + return request<T>(`${backend}${url}`, { token, params }) +} + + +export function useOrderAPI(): OrderAPI { + const { url: baseUrl, token: adminToken } = useBackendContext() + const { token: instanceToken, id, admin } = useInstanceContext() + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const createOrder = async (data: MerchantBackend.Orders.PostOrderRequest): Promise<HttpResponseOk<MerchantBackend.Orders.PostOrderResponse>> => { + const res = await request<MerchantBackend.Orders.PostOrderResponse>(`${url}/private/orders`, { + method: 'post', + token, + data + }) + await mutateAll(/@"\/private\/orders"@/) + return res + } + const refundOrder = async (orderId: string, data: MerchantBackend.Orders.RefundRequest): Promise<HttpResponseOk<MerchantBackend.Orders.MerchantRefundResponse>> => { + mutateAll(/@"\/private\/orders"@/) + return request<MerchantBackend.Orders.MerchantRefundResponse>(`${url}/private/orders/${orderId}/refund`, { + method: 'post', + token, + data + }) + + // return res + } + + const forgetOrder = async (orderId: string, data: MerchantBackend.Orders.ForgetRequest): Promise<HttpResponseOk<void>> => { + mutateAll(/@"\/private\/orders"@/) + return request(`${url}/private/orders/${orderId}/forget`, { + method: 'patch', + token, + data + }) + + } + const deleteOrder = async (orderId: string): Promise<HttpResponseOk<void>> => { + mutateAll(/@"\/private\/orders"@/) + return request(`${url}/private/orders/${orderId}`, { + method: 'delete', + token + }) + } + + const getPaymentURL = async (orderId: string): Promise<HttpResponseOk<string>> => { + return request<MerchantBackend.Orders.MerchantOrderStatusResponse>(`${url}/private/orders/${orderId}`, { + method: 'get', + token + }).then((res) => { + const url = res.data.order_status === "unpaid" ? res.data.taler_pay_uri : res.data.contract_terms.fulfillment_url + const response: HttpResponseOk<string> = res as any + response.data = url || '' + return response + }) + } + + return { createOrder, forgetOrder, deleteOrder, refundOrder, getPaymentURL } +} + +export function useOrderDetails(oderId: string): HttpResponse<MerchantBackend.Orders.MerchantOrderStatusResponse> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Orders.MerchantOrderStatusResponse>, HttpError>([`/private/orders/${oderId}`, token, url], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + +export interface InstanceOrderFilter { + paid?: YesOrNo; + refunded?: YesOrNo; + wired?: YesOrNo; + date?: Date; +} + +export function useInstanceOrders(args?: InstanceOrderFilter, updateFilter?: (d: Date) => void): HttpResponsePaginated<MerchantBackend.Orders.OrderHistory> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const [pageBefore, setPageBefore] = useState(1) + const [pageAfter, setPageAfter] = useState(1) + + const totalAfter = pageAfter * PAGE_SIZE; + const totalBefore = args?.date ? pageBefore * PAGE_SIZE : 0; + + /** + * FIXME: this can be cleaned up a little + * + * the logic of double query should be inside the orderFetch so from the hook perspective and cache + * is just one query and one error status + */ + const { data: beforeData, error: beforeError, isValidating: loadingBefore } = useSWR<HttpResponseOk<MerchantBackend.Orders.OrderHistory>, HttpError>( + [`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, args?.date, totalBefore], + orderFetcher, + ) + const { data: afterData, error: afterError, isValidating: loadingAfter } = useSWR<HttpResponseOk<MerchantBackend.Orders.OrderHistory>, HttpError>( + [`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, args?.date, -totalAfter], + orderFetcher, + ) + + //this will save last result + const [lastBefore, setLastBefore] = useState<HttpResponse<MerchantBackend.Orders.OrderHistory>>({ loading: true }) + const [lastAfter, setLastAfter] = useState<HttpResponse<MerchantBackend.Orders.OrderHistory>>({ loading: true }) + useEffect(() => { + if (afterData) setLastAfter(afterData) + if (beforeData) setLastBefore(beforeData) + }, [afterData, beforeData]) + + // this has problems when there are some ids missing + + if (beforeError) return beforeError + if (afterError) return afterError + + + const pagination = { + isReachingEnd: afterData && afterData.data.orders.length < totalAfter, + isReachingStart: (!args?.date) || (beforeData && beforeData.data.orders.length < totalBefore), + loadMore: () => { + if (!afterData) return + if (afterData.data.orders.length < MAX_RESULT_SIZE) { + setPageAfter(pageAfter + 1) + } else { + const from = afterData.data.orders[afterData.data.orders.length - 1].timestamp.t_s + if (from && updateFilter) updateFilter(new Date(from)) + } + }, + loadMorePrev: () => { + if (!beforeData) return + if (beforeData.data.orders.length < MAX_RESULT_SIZE) { + setPageBefore(pageBefore + 1) + } else if (beforeData) { + const from = beforeData.data.orders[beforeData.data.orders.length - 1].timestamp.t_s + if (from && updateFilter) updateFilter(new Date(from)) + } + }, + } + + const orders = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.orders.slice().reverse().concat((afterData || lastAfter).data.orders) + if (loadingAfter || loadingBefore) return { loading: true, data: { orders } } + if (beforeData && afterData) { + return { ok: true, data: { orders }, ...pagination } + } + return { loading: true } + +} + diff --git a/packages/merchant-backend-ui/src/hooks/product.ts b/packages/merchant-backend-ui/src/hooks/product.ts new file mode 100644 index 000000000..4fc8bccb7 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/product.ts @@ -0,0 +1,223 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { useEffect } from "preact/hooks"; +import useSWR, { trigger, useSWRInfinite, cache, mutate } from "swr"; +import { useBackendContext } from "../context/backend"; +// import { useFetchContext } from '../context/fetch'; +import { useInstanceContext } from "../context/instance"; +import { MerchantBackend, WithId } from "../declaration"; +import { + fetcher, + HttpError, + HttpResponse, + HttpResponseOk, + mutateAll, + request, +} from "./backend"; + +export interface ProductAPI { + createProduct: ( + data: MerchantBackend.Products.ProductAddDetail + ) => Promise<void>; + updateProduct: ( + id: string, + data: MerchantBackend.Products.ProductPatchDetail + ) => Promise<void>; + deleteProduct: (id: string) => Promise<void>; + lockProduct: ( + id: string, + data: MerchantBackend.Products.LockRequest + ) => Promise<void>; +} + +export function useProductAPI(): ProductAPI { + const { url: baseUrl, token: adminToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin + ? { + url: baseUrl, + token: adminToken, + } + : { + url: `${baseUrl}/instances/${id}`, + token: instanceToken, + }; + + const createProduct = async ( + data: MerchantBackend.Products.ProductAddDetail + ): Promise<void> => { + await request(`${url}/private/products`, { + method: "post", + token, + data, + }); + + await mutateAll(/@"\/private\/products"@/, null); + }; + + const updateProduct = async ( + productId: string, + data: MerchantBackend.Products.ProductPatchDetail + ): Promise<void> => { + const r = await request(`${url}/private/products/${productId}`, { + method: "patch", + token, + data, + }); + + await mutateAll(/@"\/private\/products\/.*"@/); + return Promise.resolve(); + }; + + const deleteProduct = async (productId: string): Promise<void> => { + await request(`${url}/private/products/${productId}`, { + method: "delete", + token, + }); + + await mutateAll(/@"\/private\/products"@/); + }; + + const lockProduct = async ( + productId: string, + data: MerchantBackend.Products.LockRequest + ): Promise<void> => { + await request(`${url}/private/products/${productId}/lock`, { + method: "post", + token, + data, + }); + + await mutateAll(/@"\/private\/products"@/); + }; + + return { createProduct, updateProduct, deleteProduct, lockProduct }; +} + +export function useInstanceProducts(): HttpResponse< + (MerchantBackend.Products.ProductDetail & WithId)[] +> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + // const { useSWR, useSWRInfinite } = useFetchContext(); + + const { url, token } = !admin + ? { + url: baseUrl, + token: baseToken, + } + : { + url: `${baseUrl}/instances/${id}`, + token: instanceToken, + }; + + const { + data: list, + error: listError, + isValidating: listLoading, + } = useSWR< + HttpResponseOk<MerchantBackend.Products.InventorySummaryResponse>, + HttpError + >([`/private/products`, token, url], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }); + + const { + data: products, + error: productError, + setSize, + size, + } = useSWRInfinite< + HttpResponseOk<MerchantBackend.Products.ProductDetail>, + HttpError + >( + (pageIndex: number) => { + if (!list?.data || !list.data.products.length || listError || listLoading) + return null; + return [ + `/private/products/${list.data.products[pageIndex].product_id}`, + token, + url, + ]; + }, + fetcher, + { + revalidateAll: true, + } + ); + + useEffect(() => { + if (list?.data && list.data.products.length > 0) { + setSize(list.data.products.length); + } + }, [list?.data.products.length, listLoading]); + + if (listLoading) return { loading: true, data: [] }; + if (listError) return listError; + if (productError) return productError; + if (list?.data && list.data.products.length === 0) { + return { ok: true, data: [] }; + } + if (products) { + const dataWithId = products.map((d) => { + //take the id from the queried url + return { + ...d.data, + id: d.info?.url.replace(/.*\/private\/products\//, "") || "", + }; + }); + return { ok: true, data: dataWithId }; + } + return { loading: true }; +} + +export function useProductDetails( + productId: string +): HttpResponse<MerchantBackend.Products.ProductDetail> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin + ? { + url: baseUrl, + token: baseToken, + } + : { + url: `${baseUrl}/instances/${id}`, + token: instanceToken, + }; + + const { data, error, isValidating } = useSWR< + HttpResponseOk<MerchantBackend.Products.ProductDetail>, + HttpError + >([`/private/products/${productId}`, token, url], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }); + + if (isValidating) return { loading: true, data: data?.data }; + if (data) return data; + if (error) return error; + return { loading: true }; +} diff --git a/packages/merchant-backend-ui/src/hooks/tips.ts b/packages/merchant-backend-ui/src/hooks/tips.ts new file mode 100644 index 000000000..345e1faa5 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/tips.ts @@ -0,0 +1,159 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import useSWR from 'swr'; +import { useBackendContext } from '../context/backend'; +import { useInstanceContext } from '../context/instance'; +import { MerchantBackend } from '../declaration'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; + + +export function useReservesAPI(): ReserveMutateAPI { + const { url: baseUrl, token: adminToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const createReserve = async (data: MerchantBackend.Tips.ReserveCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>> => { + const res = await request<MerchantBackend.Tips.ReserveCreateConfirmation>(`${url}/private/reserves`, { + method: 'post', + token, + data + }); + + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + const authorizeTipReserve = async (pub: string, data: MerchantBackend.Tips.TipCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => { + const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(`${url}/private/reserves/${pub}/authorize-tip`, { + method: 'post', + token, + data + }); + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + const authorizeTip = async (data: MerchantBackend.Tips.TipCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => { + const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(`${url}/private/tips`, { + method: 'post', + token, + data + }); + + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + const deleteReserve = async (pub: string): Promise<HttpResponse<void>> => { + const res = await request<void>(`${url}/private/reserves/${pub}`, { + method: 'delete', + token, + }); + + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + + return { createReserve, authorizeTip, authorizeTipReserve, deleteReserve }; +} + +export interface ReserveMutateAPI { + createReserve: (data: MerchantBackend.Tips.ReserveCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>>; + authorizeTipReserve: (id: string, data: MerchantBackend.Tips.TipCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>; + authorizeTip: (data: MerchantBackend.Tips.TipCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>; + deleteReserve: (id: string) => Promise<HttpResponse<void>>; +} + +export function useInstanceTips(): HttpResponse<MerchantBackend.Tips.TippingReserveStatus> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.TippingReserveStatus>, HttpError>([`/private/reserves`, token, url], fetcher) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + + +export function useReserveDetails(reserveId: string): HttpResponse<MerchantBackend.Tips.ReserveDetail> { + const { url: baseUrl } = useBackendContext(); + const { token, id: instanceId, admin } = useInstanceContext(); + + const url = !admin ? baseUrl : `${baseUrl}/instances/${instanceId}` + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.ReserveDetail>, HttpError>([`/private/reserves/${reserveId}`, token, url], reserveDetailFetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + +export function useTipDetails(tipId: string): HttpResponse<MerchantBackend.Tips.TipDetails> { + const { url: baseUrl } = useBackendContext(); + const { token, id: instanceId, admin } = useInstanceContext(); + + const url = !admin ? baseUrl : `${baseUrl}/instances/${instanceId}` + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.TipDetails>, HttpError>([`/private/tips/${tipId}`, token, url], tipsDetailFetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + +export function reserveDetailFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { + return request<T>(`${backend}${url}`, { token, params: { + tips: 'yes' + } }) +} + +export function tipsDetailFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { + return request<T>(`${backend}${url}`, { token, params: { + pickups: 'yes' + } }) +} diff --git a/packages/merchant-backend-ui/src/hooks/transfer.ts b/packages/merchant-backend-ui/src/hooks/transfer.ts new file mode 100644 index 000000000..482f00dc5 --- /dev/null +++ b/packages/merchant-backend-ui/src/hooks/transfer.ts @@ -0,0 +1,150 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { MerchantBackend } from '../declaration'; +import { useBackendContext } from '../context/backend'; +import { request, mutateAll, HttpResponse, HttpError, HttpResponseOk, HttpResponsePaginated } from './backend'; +import useSWR from 'swr'; +import { useInstanceContext } from '../context/instance'; +import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants'; +import { useEffect, useState } from 'preact/hooks'; + +async function transferFetcher<T>(url: string, token: string, backend: string, payto_uri?: string, verified?: string, position?: string, delta?: number): Promise<HttpResponseOk<T>> { + const params: any = {} + if (payto_uri !== undefined) params.payto_uri = payto_uri + if (verified !== undefined) params.verified = verified + if (delta !== undefined) { + // if (delta > 0) { + // params.after = searchDate?.getTime() + // } else { + // params.before = searchDate?.getTime() + // } + params.limit = delta + } + if (position !== undefined) params.offset = position + + return request<T>(`${backend}${url}`, { token, params }) +} + +export function useTransferAPI(): TransferAPI { + const { url: baseUrl, token: adminToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const informTransfer = async (data: MerchantBackend.Transfers.TransferInformation): Promise<HttpResponseOk<MerchantBackend.Transfers.MerchantTrackTransferResponse>> => { + mutateAll(/@"\/private\/transfers"@/); + + return request<MerchantBackend.Transfers.MerchantTrackTransferResponse>(`${url}/private/transfers`, { + method: 'post', + token, + data + }); + }; + + return { informTransfer }; +} + +export interface TransferAPI { + informTransfer: (data: MerchantBackend.Transfers.TransferInformation) => Promise<HttpResponseOk<MerchantBackend.Transfers.MerchantTrackTransferResponse>>; +} + +export interface InstanceTransferFilter { + payto_uri?: string; + verified?: 'yes' | 'no'; + position?: string; +} + + +export function useInstanceTransfers(args?: InstanceTransferFilter, updatePosition?: (id: string) => void): HttpResponsePaginated<MerchantBackend.Transfers.TransferList> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const [pageBefore, setPageBefore] = useState(1) + const [pageAfter, setPageAfter] = useState(1) + + const totalAfter = pageAfter * PAGE_SIZE; + const totalBefore = args?.position !== undefined ? pageBefore * PAGE_SIZE : 0; + + /** + * FIXME: this can be cleaned up a little + * + * the logic of double query should be inside the orderFetch so from the hook perspective and cache + * is just one query and one error status + */ + const { data: beforeData, error: beforeError, isValidating: loadingBefore } = useSWR<HttpResponseOk<MerchantBackend.Transfers.TransferList>, HttpError>( + [`/private/transfers`, token, url, args?.payto_uri, args?.verified, args?.position, totalBefore], + transferFetcher, + ) + const { data: afterData, error: afterError, isValidating: loadingAfter } = useSWR<HttpResponseOk<MerchantBackend.Transfers.TransferList>, HttpError>( + [`/private/transfers`, token, url, args?.payto_uri, args?.verified, args?.position, -totalAfter], + transferFetcher, + ) + + //this will save last result + const [lastBefore, setLastBefore] = useState<HttpResponse<MerchantBackend.Transfers.TransferList>>({ loading: true }) + const [lastAfter, setLastAfter] = useState<HttpResponse<MerchantBackend.Transfers.TransferList>>({ loading: true }) + useEffect(() => { + if (afterData) setLastAfter(afterData) + if (beforeData) setLastBefore(beforeData) + }, [afterData, beforeData]) + + // this has problems when there are some ids missing + + if (beforeError) return beforeError + if (afterError) return afterError + + const pagination = { + isReachingEnd: afterData && afterData.data.transfers.length < totalAfter, + isReachingStart: (!args?.position) || (beforeData && beforeData.data.transfers.length < totalBefore), + loadMore: () => { + if (!afterData) return + if (afterData.data.transfers.length < MAX_RESULT_SIZE) { + setPageAfter(pageAfter + 1) + } else { + const from = `${afterData.data.transfers[afterData.data.transfers.length - 1].transfer_serial_id}` + if (from && updatePosition) updatePosition(from) + } + }, + loadMorePrev: () => { + if (!beforeData) return + if (beforeData.data.transfers.length < MAX_RESULT_SIZE) { + setPageBefore(pageBefore + 1) + } else if (beforeData) { + const from = `${beforeData.data.transfers[beforeData.data.transfers.length - 1].transfer_serial_id}` + if (from && updatePosition) updatePosition(from) + } + }, + } + + const transfers = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.transfers.slice().reverse().concat((afterData || lastAfter).data.transfers) + if (loadingAfter || loadingBefore) return { loading: true, data: { transfers } } + if (beforeData && afterData) { + return { ok: true, data: { transfers }, ...pagination } + } + return { loading: true } +} + + diff --git a/packages/merchant-backend-ui/src/i18n/de.po b/packages/merchant-backend-ui/src/i18n/de.po new file mode 100644 index 000000000..6b35bd0ce --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/de.po @@ -0,0 +1,1057 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/merchant-backend-ui/src/i18n/en.po b/packages/merchant-backend-ui/src/i18n/en.po new file mode 100644 index 000000000..6b35bd0ce --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/en.po @@ -0,0 +1,1057 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/merchant-backend-ui/src/i18n/es.po b/packages/merchant-backend-ui/src/i18n/es.po new file mode 100644 index 000000000..9075d4656 --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/es.po @@ -0,0 +1,1065 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "Acceso denegado" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "Verifica que el token sea valido" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "No se pudo acceder al servidor" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "No se pudo inferir el id de la instancia con la url %1$s" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "HTTP status #%1$s: Servidor reporto un problema" + +#: src/InstanceRoutes.tsx:110 +#, fuzzy, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "Sin instancia default" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "para usar el merchant backoffice, deberΓa crear la instancia default" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "Servidir reporto un problema: HTTP status #%1$s" + +#: src/InstanceRoutes.tsx:289 +#, fuzzy, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "Login necesario" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" +"Por favor ingrese su token de autorizaciΓ³n. El token debe tener \"secret-" +"token\" y comenzar con Bearer o ApiKey" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "Confirmar" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "El valor %1$s es invalido para una URL de pago" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "elegir una fecha" + +#: src/components/form/InputDate.tsx:81 +#, fuzzy, c-format +msgid "clear" +msgstr "Limpiar" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "nunca" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "La imagen debe ser mas chica que 1 MB" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "PaΓs" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "DirecciΓ³n" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "NΓΊmero de edificio" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "Nombre de edificio" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "Calle" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "CΓ³digo postal" + +#: src/components/form/InputLocation.tsx:38 +#, fuzzy, c-format +msgid "Town location" +msgstr "UbicaciΓ³n de ciudad" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "Ciudad" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "Distrito" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "Provincia" + +#: src/components/form/InputSearchProduct.tsx:59 +#, fuzzy, c-format +msgid "Product id" +msgstr "Id de producto" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "Descripcion" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "Nombre" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "Cargando..." + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "No se encontraron productos" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "Sin resultados" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "Borrando" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "Cambiando" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "Administrar token" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "Actualizar" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "Eliminar" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "Cancelar" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "Administrar stock" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "Inifinito" + +#: src/components/form/InputStock.tsx:105 +#, fuzzy, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "no puede ser mayor al stock actual %1$s" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "stock actual cambiarΓ‘ desde %1$s a %2$s" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "stock actual seguirΓ‘ en %1$s" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "Ingresando" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "Perdido" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "Actual" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "sin stock" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "PrΓ³ximo reabastecimiento" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "DirecciΓ³n de entrega" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "este producto no tiene impuestos" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "Monto" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "Moneda y valor separado por dos puntos" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "Agregar" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "Instancia" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "ConfiguraciΓ³n" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, fuzzy, c-format +msgid "Orders" +msgstr "Ordenes" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "Productos" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "Transferencias" + +#: src/components/menu/SideBar.tsx:87 +#, fuzzy, c-format +msgid "Connection" +msgstr "ConexiΓ³n" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "Instancias" + +#: src/components/menu/SideBar.tsx:116 +#, fuzzy, c-format +msgid "New" +msgstr "Nuevo" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "Lista" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "Salir" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "Limpiar" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "deberΓan ser iguales" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "no puede ser igual al anterior" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" +"EstΓ‘ actualizando el token de autorizaciΓ³n para la instancia %1$s con id %2$s" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "Viejo token" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "Nuevo token" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" +"Limpiar el token de autorizaciΓ³n significa acceso publico a la instancia" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "ID" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "Imagen" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "Unidad" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "Precio" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "Stock" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "Impuesto" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "Servidor no encontrado" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "No se pudo aceder al servidor" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "Error inesperado" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "Token de autorizaciΓ³n" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "DirecciΓ³n de cuenta" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "Impuesto mΓ‘ximo de deposito por omisiΓ³n" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "Impuesto mΓ‘ximo de transferencia por omisiΓ³n" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "AmortizaciΓ³n de impuesto de transferencia por omisiΓ³n" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "JurisdicciΓ³n" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "Retrazo de pago por omisiΓ³n" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "Retrazo de transferencia por omisiΓ³n" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "no se pudo crear la instancia" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, fuzzy, c-format +msgid "Delete" +msgstr "Borrando" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "No hay instancias todavΓan, agregue mas presionando el signo +" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "Productos de inventario" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "Precio total" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "Impuesto total" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "Precio de la orden" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, fuzzy, c-format +msgid "Net" +msgstr "Neto" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "Resumen" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "Opciones de pago" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "Plazo de reembolso automΓ‘tico" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "Plazo de reembolso" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "Plazo de pago" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "Fecha de entrega" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, fuzzy, c-format +msgid "Location" +msgstr "UbicaciΓ³n" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "Impuesto mΓ‘ximo" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "Impuesto de transferencia mΓ‘ximo" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "AmortizaciΓ³n de impuesto de transferencia" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "URL de completitud" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "InformaciΓ³n extra" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "seleccione un producto primero" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, fuzzy, c-format +msgid "should be greater than 0" +msgstr "La imagen debe ser mas chica que 1 MB" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" +"no puede ser mayor al stock actual y la cantidad previamente agregada. " +"mΓ‘ximo: %1$s" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "no puede ser mayor al stock actual %1$s" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "Cantidad" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "Orden" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "reclamado" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "copiar url" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "pagar en" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "creado" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "CronologΓa" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "Detalles de pago" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, fuzzy, c-format +msgid "Order status" +msgstr "Estado de orden" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, fuzzy, c-format +msgid "Product list" +msgstr "Lista de producto" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "pagados" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "transferido" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "reembolzado" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "reembolzar" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "Monto reembolzado" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "Total depositado" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "impago" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "URL de estado de orden" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "URI de pago" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" +"Estado de orden desconocido. Esto es un error, por favor contacte a su " +"administrador" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "reembolzo creado satisfactoriamente" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, fuzzy, c-format +msgid "could not create the refund" +msgstr "No se pudo aceder al servidor" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "cargar nuevas ordenes" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "Fecha" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "Reembolzar" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "cargar viejas ordenes" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "No se enconraron ordenes" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "fecha" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "monto" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "razΓ³n" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "MΓ‘ximo reembolzable:" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "RazΓ³n" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "duplicado" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "pedido por el consumidor" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "otro" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "ir a id de orden" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "Pagado" + +#: src/paths/instance/orders/list/index.tsx:108 +#, fuzzy, c-format +msgid "Refunded" +msgstr "Reembolzado" + +#: src/paths/instance/orders/list/index.tsx:109 +#, fuzzy, c-format +msgid "Not wired" +msgstr "No transferido" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "Todo" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "no se pudo crear el producto" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "Venta" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "Ganancia" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "Vendido" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "producto actualizado correctamente" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "no se pudo actualizar el producto" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "producto fue eliminado correctamente" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "no se pudo eliminar el producto" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "Propinas" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "No hay propinas todavΓa, agregar mas presionando el signo +" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "no puede ser vacΓo" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "verificar el id, no parece vΓ‘lido" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "deberΓa tener 52 caracteres, actualmente %1$s" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "La URL no tiene el formato correcto" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, fuzzy, c-format +msgid "Transfer ID" +msgstr "Transferencias" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, fuzzy, c-format +msgid "Account Address" +msgstr "DirecciΓ³n de cuenta" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "URL del Exchange" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, fuzzy, c-format +msgid "could not inform transfer" +msgstr "no se pudo crear la instancia" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, fuzzy, c-format +msgid "load newer transfers" +msgstr "cargar nuevas ordenes" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "CrΓ©dito" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, fuzzy, c-format +msgid "Confirmed" +msgstr "Confirmar" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "Verificado" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, fuzzy, c-format +msgid "Executed at" +msgstr "creado" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "si" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "no" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "desconocido" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, fuzzy, c-format +msgid "load older transfers" +msgstr "cargar viejas transferencias" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "No hay transferencias todavΓa, agregar mas presionando el signo +" diff --git a/packages/merchant-backend-ui/src/i18n/fr.po b/packages/merchant-backend-ui/src/i18n/fr.po new file mode 100644 index 000000000..6b35bd0ce --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/fr.po @@ -0,0 +1,1057 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/merchant-backend-ui/src/i18n/index.tsx b/packages/merchant-backend-ui/src/i18n/index.tsx new file mode 100644 index 000000000..63c8e1934 --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/index.tsx @@ -0,0 +1,203 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * Translation helpers for React components and template literals. + */ + +/** + * Imports + */ +import { ComponentChild, ComponentChildren, h, Fragment, VNode } from "preact"; + +import { useTranslationContext } from "../context/translation"; + +export function useTranslator() { + const ctx = useTranslationContext(); + const jed = ctx.handler + return function str(stringSeq: TemplateStringsArray, ...values: any[]): string { + const s = toI18nString(stringSeq); + if (!s) return s + const tr = jed + .translate(s) + .ifPlural(1, s) + .fetch(...values); + return tr; + } +} + + +/** + * Convert template strings to a msgid + */ + function toI18nString(stringSeq: ReadonlyArray<string>): string { + let s = ""; + for (let i = 0; i < stringSeq.length; i++) { + s += stringSeq[i]; + if (i < stringSeq.length - 1) { + s += `%${i + 1}$s`; + } + } + return s; +} + + +interface TranslateSwitchProps { + target: number; + children: ComponentChildren; +} + +function stringifyChildren(children: ComponentChildren): string { + let n = 1; + const ss = (children instanceof Array ? children : [children]).map((c) => { + if (typeof c === "string") { + return c; + } + return `%${n++}$s`; + }); + const s = ss.join("").replace(/ +/g, " ").trim(); + return s; +} + +interface TranslateProps { + children: ComponentChildren; + /** + * Component that the translated element should be wrapped in. + * Defaults to "div". + */ + wrap?: any; + + /** + * Props to give to the wrapped component. + */ + wrapProps?: any; +} + +function getTranslatedChildren( + translation: string, + children: ComponentChildren, +): ComponentChild[] { + const tr = translation.split(/%(\d+)\$s/); + const childArray = children instanceof Array ? children : [children]; + // Merge consecutive string children. + const placeholderChildren = Array<ComponentChild>(); + for (let i = 0; i < childArray.length; i++) { + const x = childArray[i]; + if (x === undefined) { + continue; + } else if (typeof x === "string") { + continue; + } else { + placeholderChildren.push(x); + } + } + const result = Array<ComponentChild>(); + for (let i = 0; i < tr.length; i++) { + if (i % 2 == 0) { + // Text + result.push(tr[i]); + } else { + const childIdx = Number.parseInt(tr[i],10) - 1; + result.push(placeholderChildren[childIdx]); + } + } + return result; +} + +/** + * Translate text node children of this component. + * If a child component might produce a text node, it must be wrapped + * in a another non-text element. + * + * Example: + * ``` + * <Translate> + * Hello. Your score is <span><PlayerScore player={player} /></span> + * </Translate> + * ``` + */ +export function Translate({ children }: TranslateProps): VNode { + const s = stringifyChildren(children); + const ctx = useTranslationContext() + const translation: string = ctx.handler.ngettext(s, s, 1); + const result = getTranslatedChildren(translation, children) + return <Fragment>{result}</Fragment>; +} + +/** + * Switch translation based on singular or plural based on the target prop. + * Should only contain TranslateSingular and TransplatePlural as children. + * + * Example: + * ``` + * <TranslateSwitch target={n}> + * <TranslateSingular>I have {n} apple.</TranslateSingular> + * <TranslatePlural>I have {n} apples.</TranslatePlural> + * </TranslateSwitch> + * ``` + */ +export function TranslateSwitch({ children, target }: TranslateSwitchProps) { + let singular: VNode<TranslationPluralProps> | undefined; + let plural: VNode<TranslationPluralProps> | undefined; + // const children = this.props.children; + if (children) { + (children instanceof Array ? children : [children]).forEach((child: any) => { + if (child.type === TranslatePlural) { + plural = child; + } + if (child.type === TranslateSingular) { + singular = child; + } + }); + } + if (!singular || !plural) { + console.error("translation not found"); + return h("span", {}, ["translation not found"]); + } + singular.props.target = target; + plural.props.target = target; + // We're looking up the translation based on the + // singular, even if we must use the plural form. + return singular; +} + +interface TranslationPluralProps { + children: ComponentChildren; + target: number; +} + +/** + * See [[TranslateSwitch]]. + */ +export function TranslatePlural({ children, target }: TranslationPluralProps): VNode { + const s = stringifyChildren(children); + const ctx = useTranslationContext() + const translation = ctx.handler.ngettext(s, s, 1); + const result = getTranslatedChildren(translation, children); + return <Fragment>{result}</Fragment>; +} + +/** + * See [[TranslateSwitch]]. + */ +export function TranslateSingular({ children, target }: TranslationPluralProps): VNode { + const s = stringifyChildren(children); + const ctx = useTranslationContext() + const translation = ctx.handler.ngettext(s, s, target); + const result = getTranslatedChildren(translation, children); + return <Fragment>{result}</Fragment>; + +} diff --git a/packages/merchant-backend-ui/src/i18n/it.po b/packages/merchant-backend-ui/src/i18n/it.po new file mode 100644 index 000000000..6b35bd0ce --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/it.po @@ -0,0 +1,1057 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/merchant-backend-ui/src/i18n/poheader b/packages/merchant-backend-ui/src/i18n/poheader new file mode 100644 index 000000000..ee3fcd7be --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/poheader @@ -0,0 +1,27 @@ +# This file is part of GNU Taler +# (C) 2021 Taler Systems S.A. + +# GNU Taler is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. + +# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with +# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: taler@gnu.org\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" diff --git a/packages/merchant-backend-ui/src/i18n/strings-prelude b/packages/merchant-backend-ui/src/i18n/strings-prelude new file mode 100644 index 000000000..cca13afad --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/strings-prelude @@ -0,0 +1,19 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/*eslint quote-props: ["error", "consistent"]*/ +export const strings: {[s: string]: any} = {}; + diff --git a/packages/merchant-backend-ui/src/i18n/strings.ts b/packages/merchant-backend-ui/src/i18n/strings.ts new file mode 100644 index 000000000..63e96949a --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/strings.ts @@ -0,0 +1,3445 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/*eslint quote-props: ["error", "consistent"]*/ +export const strings: {[s: string]: any} = {}; + +strings['de'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['en'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['es'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "Acceso denegado" + ], + "Check your token is valid": [ + "Verifica que el token sea valido" + ], + "Couldn't access the server.": [ + "No se pudo acceder al servidor" + ], + "Could not infer instance id from url %1$s": [ + "No se pudo inferir el id de la instancia con la url %1$s" + ], + "HTTP status #%1$s: Server reported a problem": [ + "HTTP status #%1$s: Servidor reporto un problema" + ], + "Got message: \"%1$s\" from: %2$s": [ + "Recivimos el mensaje %1$s desde %2$s" + ], + "No default instance": [ + "Sin instancia default" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "para usar el merchant backoffice, deberΓa crear la instancia default" + ], + "Server reported a problem: HTTP status #%1$s": [ + "Servidir reporto un problema: HTTP status #%1$s" + ], + "Got message: %1$s from: %2$s": [ + "Recivimos el mensaje %1$s desde %2$s" + ], + "Login required": [ + "Login necesario" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "Por favor ingrese su token de autorizaciΓ³n. El token debe tener \"secret-token\" y comenzar con Bearer o ApiKey" + ], + "Confirm": [ + "Confirmar" + ], + "The value %1$s is invalid for a payment url": [ + "El valor %1$s es invalido para una URL de pago" + ], + "pick a date": [ + "elegir una fecha" + ], + "clear": [ + "Limpiar" + ], + "never": [ + "nunca" + ], + "Image should be smaller than 1 MB": [ + "La imagen debe ser mas chica que 1 MB" + ], + "Country": [ + "PaΓs" + ], + "Address": [ + "DirecciΓ³n" + ], + "Building number": [ + "NΓΊmero de edificio" + ], + "Building name": [ + "Nombre de edificio" + ], + "Street": [ + "Calle" + ], + "Post code": [ + "CΓ³digo postal" + ], + "Town location": [ + "UbicaciΓ³n de ciudad" + ], + "Town": [ + "Ciudad" + ], + "District": [ + "Distrito" + ], + "Country subdivision": [ + "Provincia" + ], + "Product id": [ + "Id de producto" + ], + "Description": [ + "Descripcion" + ], + "Name": [ + "Nombre" + ], + "loading...": [ + "Cargando..." + ], + "no products found": [ + "No se encontraron productos" + ], + "no results": [ + "Sin resultados" + ], + "Deleting": [ + "Borrando" + ], + "Changing": [ + "Cambiando" + ], + "Manage token": [ + "Administrar token" + ], + "Update": [ + "Actualizar" + ], + "Remove": [ + "Eliminar" + ], + "Cancel": [ + "Cancelar" + ], + "Manage stock": [ + "Administrar stock" + ], + "Infinite": [ + "Inifinito" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "no puede ser mayor al stock actual %1$s" + ], + "current stock will change from %1$s to %2$s": [ + "stock actual cambiarΓ‘ desde %1$s a %2$s" + ], + "current stock will stay at %1$s": [ + "stock actual seguirΓ‘ en %1$s" + ], + "Incoming": [ + "Ingresando" + ], + "Lost": [ + "Perdido" + ], + "Current": [ + "Actual" + ], + "without stock": [ + "sin stock" + ], + "Next restock": [ + "PrΓ³ximo reabastecimiento" + ], + "Delivery address": [ + "DirecciΓ³n de entrega" + ], + "this product has no taxes": [ + "este producto no tiene impuestos" + ], + "Amount": [ + "Monto" + ], + "currency and value separated with colon": [ + "Moneda y valor separado por dos puntos" + ], + "Add": [ + "Agregar" + ], + "Instance": [ + "Instancia" + ], + "Settings": [ + "ConfiguraciΓ³n" + ], + "Orders": [ + "Ordenes" + ], + "Products": [ + "Productos" + ], + "Transfers": [ + "Transferencias" + ], + "Connection": [ + "ConexiΓ³n" + ], + "Instances": [ + "Instancias" + ], + "New": [ + "Nuevo" + ], + "List": [ + "Lista" + ], + "Log out": [ + "Salir" + ], + "Clear": [ + "Limpiar" + ], + "should be the same": [ + "deberΓan ser iguales" + ], + "cannot be the same as before": [ + "no puede ser igual al anterior" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "EstΓ‘ actualizando el token de autorizaciΓ³n para la instancia %1$s con id %2$s" + ], + "Old token": [ + "Viejo token" + ], + "New token": [ + "Nuevo token" + ], + "Clearing the auth token will mean public access to the instance": [ + "Limpiar el token de autorizaciΓ³n significa acceso publico a la instancia" + ], + "ID": [ + "ID" + ], + "Image": [ + "Imagen" + ], + "Unit": [ + "Unidad" + ], + "Price": [ + "Precio" + ], + "Stock": [ + "Stock" + ], + "Taxes": [ + "Impuesto" + ], + "Server not found": [ + "Servidor no encontrado" + ], + "Couldn't access the server": [ + "No se pudo aceder al servidor" + ], + "Got message %1$s from %2$s": [ + "Recivimos el mensaje %1$s desde %2$s" + ], + "Unexpected Error": [ + "Error inesperado" + ], + "Auth token": [ + "Token de autorizaciΓ³n" + ], + "Account address": [ + "DirecciΓ³n de cuenta" + ], + "Default max deposit fee": [ + "Impuesto mΓ‘ximo de deposito por omisiΓ³n" + ], + "Default max wire fee": [ + "Impuesto mΓ‘ximo de transferencia por omisiΓ³n" + ], + "Default wire fee amortization": [ + "AmortizaciΓ³n de impuesto de transferencia por omisiΓ³n" + ], + "Jurisdiction": [ + "JurisdicciΓ³n" + ], + "Default pay delay": [ + "Retrazo de pago por omisiΓ³n" + ], + "Default wire transfer delay": [ + "Retrazo de transferencia por omisiΓ³n" + ], + "could not create instance": [ + "no se pudo crear la instancia" + ], + "Delete": [ + "Borrando" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "No hay instancias todavΓan, agregue mas presionando el signo +" + ], + "Inventory products": [ + "Productos de inventario" + ], + "Total price": [ + "Precio total" + ], + "Total tax": [ + "Impuesto total" + ], + "Order price": [ + "Precio de la orden" + ], + "Net": [ + "Neto" + ], + "Summary": [ + "Resumen" + ], + "Payments options": [ + "Opciones de pago" + ], + "Auto refund deadline": [ + "Plazo de reembolso automΓ‘tico" + ], + "Refund deadline": [ + "Plazo de reembolso" + ], + "Pay deadline": [ + "Plazo de pago" + ], + "Delivery date": [ + "Fecha de entrega" + ], + "Location": [ + "UbicaciΓ³n" + ], + "Max fee": [ + "Impuesto mΓ‘ximo" + ], + "Max wire fee": [ + "Impuesto de transferencia mΓ‘ximo" + ], + "Wire fee amortization": [ + "AmortizaciΓ³n de impuesto de transferencia" + ], + "Fullfilment url": [ + "URL de completitud" + ], + "Extra information": [ + "InformaciΓ³n extra" + ], + "select a product first": [ + "seleccione un producto primero" + ], + "should be greater than 0": [ + "La imagen debe ser mas chica que 1 MB" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "no puede ser mayor al stock actual y la cantidad previamente agregada. mΓ‘ximo: %1$s" + ], + "cannot be greater than current stock %1$s": [ + "no puede ser mayor al stock actual %1$s" + ], + "Quantity": [ + "Cantidad" + ], + "Order": [ + "Orden" + ], + "claimed": [ + "reclamado" + ], + "copy url": [ + "copiar url" + ], + "pay at": [ + "pagar en" + ], + "created at": [ + "creado" + ], + "Timeline": [ + "CronologΓa" + ], + "Payment details": [ + "Detalles de pago" + ], + "Order status": [ + "Estado de orden" + ], + "Product list": [ + "Lista de producto" + ], + "paid": [ + "pagados" + ], + "wired": [ + "transferido" + ], + "refunded": [ + "reembolzado" + ], + "refund": [ + "reembolzar" + ], + "Refunded amount": [ + "Monto reembolzado" + ], + "Deposit total": [ + "Total depositado" + ], + "unpaid": [ + "impago" + ], + "Order status URL": [ + "URL de estado de orden" + ], + "Pay URI": [ + "URI de pago" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "Estado de orden desconocido. Esto es un error, por favor contacte a su administrador" + ], + "refund created successfully": [ + "reembolzo creado satisfactoriamente" + ], + "could not create the refund": [ + "No se pudo aceder al servidor" + ], + "load newer orders": [ + "cargar nuevas ordenes" + ], + "Date": [ + "Fecha" + ], + "Refund": [ + "Reembolzar" + ], + "load older orders": [ + "cargar viejas ordenes" + ], + "No orders has been found": [ + "No se enconraron ordenes" + ], + "date": [ + "fecha" + ], + "amount": [ + "monto" + ], + "reason": [ + "razΓ³n" + ], + "Max refundable:": [ + "MΓ‘ximo reembolzable:" + ], + "Reason": [ + "RazΓ³n" + ], + "duplicated": [ + "duplicado" + ], + "requested by the customer": [ + "pedido por el consumidor" + ], + "other": [ + "otro" + ], + "go to order id": [ + "ir a id de orden" + ], + "Paid": [ + "Pagado" + ], + "Refunded": [ + "Reembolzado" + ], + "Not wired": [ + "No transferido" + ], + "All": [ + "Todo" + ], + "could not create product": [ + "no se pudo crear el producto" + ], + "Sell": [ + "Venta" + ], + "Profit": [ + "Ganancia" + ], + "Sold": [ + "Vendido" + ], + "product updated successfully": [ + "producto actualizado correctamente" + ], + "could not update the product": [ + "no se pudo actualizar el producto" + ], + "product delete successfully": [ + "producto fue eliminado correctamente" + ], + "could not delete the product": [ + "no se pudo eliminar el producto" + ], + "Tips": [ + "Propinas" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "No hay propinas todavΓa, agregar mas presionando el signo +" + ], + "cannot be empty": [ + "no puede ser vacΓo" + ], + "check the id, doest look valid": [ + "verificar el id, no parece vΓ‘lido" + ], + "should have 52 characters, current %1$s": [ + "deberΓa tener 52 caracteres, actualmente %1$s" + ], + "URL doesn't have the right format": [ + "La URL no tiene el formato correcto" + ], + "Transfer ID": [ + "Transferencias" + ], + "Account Address": [ + "DirecciΓ³n de cuenta" + ], + "Exchange URL": [ + "URL del Exchange" + ], + "could not inform transfer": [ + "no se pudo crear la instancia" + ], + "load newer transfers": [ + "cargar nuevas ordenes" + ], + "Credit": [ + "CrΓ©dito" + ], + "Confirmed": [ + "Confirmar" + ], + "Verified": [ + "Verificado" + ], + "Executed at": [ + "creado" + ], + "yes": [ + "si" + ], + "no": [ + "no" + ], + "unknown": [ + "desconocido" + ], + "load older transfers": [ + "cargar viejas transferencias" + ], + "There is no transfer yet, add more pressing the + sign": [ + "No hay transferencias todavΓa, agregar mas presionando el signo +" + ] + } + } +}; + +strings['fr'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['it'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['sv'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + diff --git a/packages/merchant-backend-ui/src/i18n/sv.po b/packages/merchant-backend-ui/src/i18n/sv.po new file mode 100644 index 000000000..6b35bd0ce --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/sv.po @@ -0,0 +1,1057 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/merchant-backend-ui/src/i18n/taler-merchant-backoffice.pot b/packages/merchant-backend-ui/src/i18n/taler-merchant-backoffice.pot new file mode 100644 index 000000000..21fd863b0 --- /dev/null +++ b/packages/merchant-backend-ui/src/i18n/taler-merchant-backoffice.pot @@ -0,0 +1,1054 @@ +# This file is part of GNU Taler +# (C) 2021 Taler Systems S.A. +# GNU Taler is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with +# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:258 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:65 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/merchant-backend-ui/src/index.tsx b/packages/merchant-backend-ui/src/index.tsx new file mode 100644 index 000000000..275f63371 --- /dev/null +++ b/packages/merchant-backend-ui/src/index.tsx @@ -0,0 +1,61 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, VNode, Fragment } from 'preact'; +import { BackendContextProvider } from './context/backend'; +import { TranslationProvider } from './context/translation'; +// import { Page as RequestPayment } from './RequestPayment'; +import "./css/pure-min.css" +import { Route, Router } from 'preact-router'; +import { Footer } from './components/Footer'; +// import OfferTip from './pages/OfferTip'; +// import {OfferRefund} from './pages/OfferRefund'; +// import DepletedTip from './pages/DepletedTip'; +// import RequestPayment from './pages/RequestPayment'; +// import ShowOrderDetails from './pages/ShowOrderDetails'; + +export default function Application(): VNode { + return ( + // <FetchContextProvider> + <BackendContextProvider> + <TranslationProvider> + <ApplicationStatusRoutes /> + </TranslationProvider> + </BackendContextProvider> + // </FetchContextProvider> + ); +} + +function ApplicationStatusRoutes(): VNode { + return <Fragment> + <Router> + {/* <Route path="offer_tip" component={OfferTip} /> + <Route path="offer_refund" component={OfferRefund} /> + <Route path="depleted_tip" component={DepletedTip} /> + <Route path="request_payment" component={RequestPayment} /> + <Route path="show_order_details" component={ShowOrderDetails} /> */} + <Route default component={() => <div> + hello! + </div>} /> + </Router> + <Footer /> + </Fragment> +} diff --git a/packages/merchant-backend-ui/src/pages/DepletedTip.stories.tsx b/packages/merchant-backend-ui/src/pages/DepletedTip.stories.tsx new file mode 100644 index 000000000..c20f6dc18 --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/DepletedTip.stories.tsx @@ -0,0 +1,40 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, VNode, FunctionalComponent } from 'preact'; +import { DepletedTip as TestedComponent } from './DepletedTip'; + + +export default { + title: 'DepletedTip', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Example = createExample(TestedComponent, { +}); diff --git a/packages/merchant-backend-ui/src/pages/DepletedTip.tsx b/packages/merchant-backend-ui/src/pages/DepletedTip.tsx new file mode 100644 index 000000000..756b08d6a --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/DepletedTip.tsx @@ -0,0 +1,60 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import { Fragment, h, render, VNode } from 'preact'; +import { render as renderToString } from 'preact-render-to-string'; +import { Footer } from '../components/Footer'; +import "../css/pure-min.css"; +import "../css/style.css"; +import { Page } from '../styled'; + +function Head(): VNode { + return <title>Status of your tip</title> +} + +export function DepletedTip(): VNode { + return <Page> + <section> + <h1>Tip already collected</h1> + <div> + You have already collected this tip. + </div> + </section> + <Footer /> + </Page> +} + +export function mount(): void { + try { + render(<DepletedTip />, document.body); + } catch (e) { + console.error("got error", e); + if (e instanceof Error) { + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } + } +} + +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<DepletedTip />) + } +} diff --git a/packages/merchant-backend-ui/src/pages/OfferRefund.stories.tsx b/packages/merchant-backend-ui/src/pages/OfferRefund.stories.tsx new file mode 100644 index 000000000..92694f867 --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/OfferRefund.stories.tsx @@ -0,0 +1,45 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, VNode, FunctionalComponent } from 'preact'; +import { createSVG } from '../components/QR'; +import { OfferRefund as TestedComponent } from './OfferRefund'; + + +export default { + title: 'OfferRefund', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +const REFUND_URI_EXAMPLE = 'taler://pay/backend.demo.taler.net/instances/blog/2021.249-022NW2KG88QGA/def537eb-00c2-4a8b-8a17-0be034d118d3?c=2Y4N4PMST7KYAPS83428GTPCD4' + +export const Example = createExample(TestedComponent, { + refundURI: REFUND_URI_EXAMPLE, + qr_code: createSVG(REFUND_URI_EXAMPLE) +}); diff --git a/packages/merchant-backend-ui/src/pages/OfferRefund.tsx b/packages/merchant-backend-ui/src/pages/OfferRefund.tsx new file mode 100644 index 000000000..14c9372c2 --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/OfferRefund.tsx @@ -0,0 +1,154 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import { Fragment, h, render, VNode } from 'preact'; +import { render as renderToString } from 'preact-render-to-string'; +import { useEffect } from 'preact/hooks'; +import { Footer } from '../components/Footer'; +import { QR } from '../components/QR'; +import "../css/pure-min.css"; +import "../css/style.css"; +import { Page, QRPlaceholder, WalletLink } from '../styled'; + +/** + * This page creates a refund offer QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - order_status_url + * - taler_refund_qrcode_svg + * - taler_refund_uri + * + * request params: + * - refund_uri + * - order_status_url + */ + +interface Props { + refundURI?: string; + order_status_url?: string; + qr_code?: string; +} + +function Head({ order_summary }: { order_summary?: string }): VNode { + return <Fragment> + <meta charSet="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title>Refund available for {order_summary ? order_summary : `{{ order_summary }}`}</title> + </Fragment> +} + +export function OfferRefund({ refundURI, qr_code, order_status_url }: Props): VNode { + useEffect(() => { + let checkUrl: URL; + try { + checkUrl = new URL(order_status_url ? order_status_url : "{{& order_status_url }}"); + } catch (e) { + return; + } + checkUrl.searchParams.set("await_refund_obtained", "yes"); + const delayMs = 500; + function check() { + let retried = false; + function retryOnce() { + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 200) { + try { + const resp = JSON.parse(req.responseText); + if (!resp.refund_pending) { + window.location.reload(); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + setTimeout(retryOnce, delayMs); + } + }; + req.onerror = function () { + setTimeout(retryOnce, delayMs); + } + req.open("GET", checkUrl.href); + req.send(); + } + + setTimeout(check, delayMs); + }) + return <Page> + <section> + <h1>Collect Taler refund</h1> + <p> + Scan this QR code with your Taler mobile wallet: + </p> + <QRPlaceholder dangerouslySetInnerHTML={{ __html: qr_code ? qr_code : `{{{ taler_refund_qrcode_svg }}}` }} /> + <p> + <WalletLink href={refundURI ? refundURI : `{{ taler_refund_uri }}`}> + Or open your Taller wallet + </WalletLink> + </p> + <p> + <a href="https://wallet.taler.net/">Don't have a Taler wallet yet? Install it!</a> + </p> + </section> + <Footer /> + </Page> +} + +export function mount(): void { + try { + const fromLocation = new URL(window.location.href).searchParams + const os = fromLocation.get('order_summary') || undefined; + if (os) { + render(<Head order_summary={os} />, document.head); + } + + const uri = fromLocation.get('refund_uri') || undefined; + const osu = fromLocation.get('order_status_url') || undefined; + const qr_code = uri ? renderToString(<QR text={uri} />) : undefined; + + render(<OfferRefund + refundURI={uri} order_status_url={osu} + qr_code={qr_code} + />, document.body); + } catch (e) { + console.error("got error", e); + if (e instanceof Error) { + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } + } +} + +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<OfferRefund />) + } +} diff --git a/packages/merchant-backend-ui/src/pages/OfferTip.stories.tsx b/packages/merchant-backend-ui/src/pages/OfferTip.stories.tsx new file mode 100644 index 000000000..dfbf71fff --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/OfferTip.stories.tsx @@ -0,0 +1,45 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, VNode, FunctionalComponent } from 'preact'; +import { createSVG } from '../components/QR'; +import { OfferTip as TestedComponent } from './OfferTip'; + + +export default { + title: 'OfferTip', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +const TIP_URI_EXAMPLE = 'taler+http://tip/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0' + +export const Example = createExample(TestedComponent, { + tipURI: TIP_URI_EXAMPLE, + qr_code: createSVG(TIP_URI_EXAMPLE) +}); diff --git a/packages/merchant-backend-ui/src/pages/OfferTip.tsx b/packages/merchant-backend-ui/src/pages/OfferTip.tsx new file mode 100644 index 000000000..ace1059ca --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/OfferTip.tsx @@ -0,0 +1,141 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import { Fragment, h, render, VNode } from 'preact'; +import { render as renderToString } from 'preact-render-to-string'; +import { useEffect } from 'preact/hooks'; +import { Footer } from '../components/Footer'; +import { QR } from '../components/QR'; +import "../css/pure-min.css"; +import "../css/style.css"; +import { Page, QRPlaceholder, WalletLink } from '../styled'; +import { ShowOrderDetails } from './ShowOrderDetails'; + + +/** + * This page creates a tip offer QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - tip_status_url + * - taler_tip_qrcode_svg + * - taler_tip_uri + * + * request params: + * - tip_uri + * - tip_status_url + */ + +interface Props { + tipURI?: string, + tip_status_url?: string, + qr_code?: string, +} + +export function Head(): VNode { + return <Fragment> + <meta charSet="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title>Tip available</title> + </Fragment> +} + +export function OfferTip({ tipURI, qr_code, tip_status_url }: Props): VNode { + useEffect(() => { + let checkUrl: URL; + try { + checkUrl = new URL(tip_status_url ? tip_status_url : "{{& tip_status_url }}"); + } catch (e) { + return; + } + + const delayMs = 500; + function check() { + let retried = false; + function retryOnce() { + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 410) { + window.location.reload(); + } + setTimeout(retryOnce, delayMs); + } + }; + req.onerror = function () { + setTimeout(retryOnce, delayMs); + } + req.open("GET", checkUrl.href); + req.send(); + } + + setTimeout(check, delayMs); + }) + return <Page> + <section> + <h1 >Collect Taler tip</h1> + <p> + Scan this QR code with your Taler mobile wallet: + </p> + <QRPlaceholder dangerouslySetInnerHTML={{ __html: qr_code ? qr_code : `{{{ taler_tip_qrcode_svg }}}` }} /> + <p> + <WalletLink href={tipURI ? tipURI : `{{ taler_tip_uri }}`}> + Or open your Taller wallet + </WalletLink> + </p> + <p> + <a href="https://wallet.taler.net/">Don't have a Taler wallet yet? Install it!</a> + </p> + </section> + <Footer /> + </Page> +} + +export function mount(): void { + try { + const fromLocation = new URL(window.location.href).searchParams + + const uri = fromLocation.get('tip_uri') || undefined + const tsu = fromLocation.get('tip_status_url') || undefined + + render(<OfferTip tipURI={uri} tip_status_url={tsu} />, document.body); + } catch (e) { + console.error("got error", e); + if (e instanceof Error) { + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } + } +} + +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<ShowOrderDetails />) + } +} diff --git a/packages/merchant-backend-ui/src/pages/RequestPayment.stories.tsx b/packages/merchant-backend-ui/src/pages/RequestPayment.stories.tsx new file mode 100644 index 000000000..5d6d79adf --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/RequestPayment.stories.tsx @@ -0,0 +1,45 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { FunctionalComponent, h } from 'preact'; +import { createSVG } from '../components/QR'; +import { RequestPayment as TestedComponent } from './RequestPayment'; + + +export default { + title: 'RequestPayment', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +const PAYTO_URI_EXAMPLE = 'taler+http://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0' + +export const Example = createExample(TestedComponent, { + payURI: 'taler+http://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0', + qr_code: createSVG(PAYTO_URI_EXAMPLE) +}); diff --git a/packages/merchant-backend-ui/src/pages/RequestPayment.tsx b/packages/merchant-backend-ui/src/pages/RequestPayment.tsx new file mode 100644 index 000000000..050755dfb --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/RequestPayment.tsx @@ -0,0 +1,196 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { Fragment, h, render, VNode } from "preact"; +import { render as renderToString } from "preact-render-to-string"; +import { useEffect } from "preact/hooks"; +import { Footer } from "../components/Footer"; +import "../css/pure-min.css"; +import "../css/style.css"; +import { QR } from "../components/QR"; +import { Page, QRPlaceholder, WalletLink } from "../styled"; + +/** + * This page creates a payment request QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - order_status_url + * - taler_pay_qrcode_svg + * - taler_pay_uri + * - order_summary + * + * request params: + * - pay_uri + * - order_summary + * - order_status_url + */ + +interface Props { + payURI?: string; + order_status_url?: string; + qr_code?: string; +} + +function Head({ order_summary }: { order_summary?: string }): VNode { + return ( + <Fragment> + <meta charSet="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title> + Payment requested for{" "} + {order_summary ? order_summary : `{{ order_summary }}`} + </title> + </Fragment> + ); +} + +export function RequestPayment({ + payURI, + qr_code, + order_status_url, +}: Props): VNode { + useEffect(() => { + const longpollDelayMs = 60 * 1000; + let checkUrl: URL; + try { + checkUrl = new URL( + order_status_url ? order_status_url : "{{& order_status_url }}" + ); + } catch (e) { + return; + } + checkUrl.searchParams.set("timeout_s", longpollDelayMs.toString()); + function check() { + let retried = false; + function retryOnce() { + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 200) { + try { + const resp = JSON.parse(req.responseText); + if (resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + if (req.status === 202) { + try { + const resp = JSON.parse(req.responseText); + if (resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + if (req.status === 402) { + try { + const resp = JSON.parse(req.responseText); + if (resp.already_paid_order_id && resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + setTimeout(retryOnce, 500); + } + }; + req.onerror = function () { + setTimeout(retryOnce, 500); + }; + req.ontimeout = function () { + setTimeout(retryOnce, 500); + }; + req.timeout = longpollDelayMs; + req.open("GET", checkUrl.href); + req.send(); + } + setTimeout(check, 500); + }); + return ( + <Page> + <section> + <h1>Pay with Taler</h1> + <p>Scan this QR code with your mobile wallet:</p> + <QRPlaceholder + dangerouslySetInnerHTML={{ + __html: qr_code ? qr_code : `{{{ taler_pay_qrcode_svg }}}`, + }} + /> + <p> + <WalletLink href={payURI ? payURI : `{{ taler_pay_uri }}`}> + Or open your Taller wallet + </WalletLink> + </p> + <p> + <a href="https://wallet.taler.net/"> + Don't have a Taler wallet yet? Install it! + </a> + </p> + </section> + <Footer /> + </Page> + ); +} + +export function mount(): void { + try { + const fromLocation = new URL(window.location.href).searchParams; + const os = fromLocation.get("order_summary") || undefined; + if (os) { + render(<Head order_summary={os} />, document.head); + } + + const uri = fromLocation.get("pay_uri") || undefined; + const osu = fromLocation.get("order_status_url") || undefined; + const qr_code = uri ? renderToString(<QR text={uri} />) : undefined; + + render( + <RequestPayment payURI={uri} order_status_url={osu} qr_code={qr_code} />, + document.body + ); + } catch (e) { + console.error("got error", e); + if (e instanceof Error) { + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } + } +} + +export function buildTimeRendering(): { head: string; body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<RequestPayment />), + }; +} diff --git a/packages/merchant-backend-ui/src/pages/ShowOrderDetails.examples.ts b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.examples.ts new file mode 100644 index 000000000..ba68397ee --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.examples.ts @@ -0,0 +1,219 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { MerchantBackend } from '../declaration'; +import { Props } from './ShowOrderDetails'; + + +const defaultContractTerms: MerchantBackend.ContractTerms = { + order_id: 'XRS8876388373', + amount: 'USD:10', + summary: 'this is a short summary', + pay_deadline: { + t_s: new Date().getTime() + 6 * 24 * 60 * 60 * 1000 + }, + merchant: { + name: 'the merchant (inc)', + address: { + country_subdivision: 'Buenos Aires', + town: 'CABA', + country: 'Argentina' + }, + jurisdiction: { + country_subdivision: 'Cordoba', + town: 'Capital', + country: 'Argentina' + }, + }, + max_fee: 'USD:0.1', + max_wire_fee: 'USD:0.2', + wire_fee_amortization: 1, + products: [], + timestamp: { + t_s: new Date().getTime() + }, + auditors: [], + exchanges: [], + h_wire: '', + merchant_base_url: 'http://merchant.base.url/', + merchant_pub: 'QWEASDQWEASD', + nonce: 'NONCE', + refund_deadline: { + t_s: new Date().getTime() + 6 * 24 * 60 * 60 * 1000 + }, + wire_method: 'x-taler-bank', + wire_transfer_deadline: { + t_s: new Date().getTime() + 3 * 24 * 60 * 60 * 1000 + }, +}; + +const inSixDays = new Date().getTime() + 6 * 24 * 60 * 60 * 1000 +const in10Minutes = new Date().getTime() + 10 * 60 * 1000 +const in15Minutes = new Date().getTime() + 15 * 60 * 1000 +const in20Minutes = new Date().getTime() + 20 * 60 * 1000 + +export const exampleData: { [name: string]: Props } = { + Simplest: { + order_summary: 'here goes the order summary', + contract_terms: defaultContractTerms, + }, + WithRefundAmount: { + order_summary: 'here goes the order summary', + refund_amount: 'USD:10', + contract_terms: defaultContractTerms, + }, + WithDeliveryDate: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + delivery_date: { + t_s: inSixDays + }, + }, + }, + WithDeliveryLocation: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + delivery_location: { + address_lines: ['addr line 1', 'addr line 2', 'addr line 3', 'addr line 4', 'addr line 5', 'addr line 6', 'addr line 7'], + building_name: 'building-name', + building_number: 'building-number', + country: 'country', + country_subdivision: 'country sub', + district: 'district', + post_code: 'post-code', + street: 'street', + town: 'town', + town_location: 'town loc', + }, + }, + }, + WithDeliveryLocationAndDate: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + delivery_location: { + address_lines: ['addr1', 'addr2', 'addr3', 'addr4', 'addr5', 'addr6', 'addr7'], + building_name: 'building-name', + building_number: 'building-number', + country: 'country', + country_subdivision: 'country sub', + district: 'district', + post_code: 'post-code', + street: 'street', + town: 'town', + town_location: 'town loc', + }, + delivery_date: { + t_s: inSixDays + }, + }, + }, + WithThreeProducts: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + products: [{ + description: 'description of the first product', + price: '5:USD', + quantity: 1, + delivery_date: { t_s: in10Minutes }, + product_id: '12333', + }, { + description: 'another description', + price: '10:USD', + quantity: 5, + unit: 't-shirt', + }, { + description: 'one last description', + price: '10:USD', + quantity: 5 + }] + } as MerchantBackend.ContractTerms + }, + WithProductWithTaxes: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + products: [{ + description: 'description of the first product', + price: '5:USD', + quantity: 1, + unit: 'beer', + delivery_date: { t_s: in10Minutes }, + product_id: '456', + taxes: [{ + name: 'VAT', tax: 'USD:1' + }], + }, { + description: 'one last description', + price: '10:USD', + quantity: 5, + product_id: '123', + unit: 'beer', + taxes: [{ + name: 'VAT', tax: 'USD:1' + }], + }] + } as MerchantBackend.ContractTerms + }, + WithExchangeList: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + exchanges: [{ + master_pub: 'ABCDEFGHIJKLMNO', + url: 'http://exchange0.taler.net' + }, { + master_pub: 'AAAAAAAAAAAAAAA', + url: 'http://exchange1.taler.net' + }, { + master_pub: 'BBBBBBBBBBBBBBB', + url: 'http://exchange2.taler.net' + }] + }, + }, + WithAuditorList: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + auditors: [{ + auditor_pub: 'ABCDEFGHIJKLMNO', + name: 'the USD auditor', + url: 'http://auditor-usd.taler.net' + }, { + auditor_pub: 'OPQRSTUVWXYZABCD', + name: 'the EUR auditor', + url: 'http://auditor-eur.taler.net' + }] + }, + }, + WithAutoRefund: { + order_summary: 'here goes the order summary', + contract_terms: { + ...defaultContractTerms, + auto_refund: { + d_us: 1000 * 60 * 60 * 26 + 1000 * 60 * 30 + } + }, + }, +} diff --git a/packages/merchant-backend-ui/src/pages/ShowOrderDetails.stories.tsx b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.stories.tsx new file mode 100644 index 000000000..6a902cc9e --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.stories.tsx @@ -0,0 +1,49 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { FunctionalComponent, h } from 'preact'; +import { ShowOrderDetails as TestedComponent } from './ShowOrderDetails'; +import { exampleData } from './ShowOrderDetails.examples'; + +export default { + title: 'ShowOrderDetails', + component: TestedComponent, + argTypes: { + }, + excludeStories: /.*Data$/, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Simplest = createExample(TestedComponent, exampleData.Simplest); +export const WithRefundAmount = createExample(TestedComponent, exampleData.WithRefundAmount); +export const WithDeliveryDate = createExample(TestedComponent, exampleData.WithDeliveryDate); +export const WithDeliveryLocation = createExample(TestedComponent, exampleData.WithDeliveryLocation); +export const WithDeliveryLocationAndDate = createExample(TestedComponent, exampleData.WithDeliveryLocationAndDate); +export const WithThreeProducts = createExample(TestedComponent, exampleData.WithThreeProducts); +export const WithAuditorList = createExample(TestedComponent, exampleData.WithAuditorList); +export const WithExchangeList = createExample(TestedComponent, exampleData.WithExchangeList); +export const WithAutoRefund = createExample(TestedComponent, exampleData.WithAutoRefund); +export const WithProductWithTaxes = createExample(TestedComponent, exampleData.WithProductWithTaxes); diff --git a/packages/merchant-backend-ui/src/pages/ShowOrderDetails.tsx b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.tsx new file mode 100644 index 000000000..aa62c2932 --- /dev/null +++ b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.tsx @@ -0,0 +1,551 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { format, formatDuration } from "date-fns"; +import { intervalToDuration } from "date-fns/esm"; +import { Fragment, h, render, VNode } from "preact"; +import { render as renderToString } from "preact-render-to-string"; +import { Footer } from "../components/Footer"; +import "../css/pure-min.css"; +import "../css/style.css"; +import { MerchantBackend } from "../declaration"; +import { Page, InfoBox, TableExpanded, TableSimple } from "../styled"; + +/** + * This page creates a payment request QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - order_summary + * - contract_terms + * - refund_amount + * + * request params: + * - refund_amount + * - contract_terms + * - order_summary + */ + +export interface Props { + btr?: boolean; // build time rendering flag + order_summary?: string; + refund_amount?: string; + contract_terms?: MerchantBackend.ContractTerms; +} + +function Head({ order_summary }: { order_summary?: string }): VNode { + return ( + <Fragment> + <meta charSet="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title> + Status of your order for{" "} + {order_summary ? order_summary : `{{ order_summary }}`} + </title> + <script>{` + var contractTermsStr = '{{{contract_terms_json}}}'; + `}</script> + </Fragment> + ); +} + +function Location({ + templateName, + location, + btr, +}: { + templateName: string; + location: MerchantBackend.Location | undefined; + btr?: boolean; +}) { + //FIXME: mustache strings show be constructed in a way that ends in the final output of the html but is not present in the + // javascript code, otherwise when mustache render engine run over the html it will also replace string in the javascript code + // that is made to run when the browser has javascript enable leading into undefined behavior. + // that's why in the next fields we are using concatenations to build the mustache placeholder. + return ( + <Fragment> + {btr && `{{` + `#${templateName}.building_name}}`} + <dd> + {location?.building_name || + (btr && `{{ ${templateName}.building_name }}`)}{" "} + {location?.building_number || + (btr && `{{ ${templateName}.building_number }}`)} + </dd> + {btr && `{{` + `/${templateName}.building_name}}`} + + {btr && `{{` + `#${templateName}.country}}`} + <dd> + {location?.country || (btr && `{{ ${templateName}.country }}`)}{" "} + {location?.country_subdivision || + (btr && `{{ ${templateName}.country_subdivision }}`)} + </dd> + {btr && `{{` + `/${templateName}.country}}`} + + {btr && `{{` + `#${templateName}.district}}`} + <dd>{location?.district || (btr && `{{ ${templateName}.district }}`)}</dd> + {btr && `{{` + `/${templateName}.district}}`} + + {btr && `{{` + `#${templateName}.post_code}}`} + <dd> + {location?.post_code || (btr && `{{ ${templateName}.post_code }}`)} + </dd> + {btr && `{{` + `/${templateName}.post_code}}`} + + {btr && `{{` + `#${templateName}.street}}`} + <dd>{location?.street || (btr && `{{ ${templateName}.street }}`)}</dd> + {btr && `{{` + `/${templateName}.street}}`} + + {btr && `{{` + `#${templateName}.town}}`} + <dd>{location?.town || (btr && `{{ ${templateName}.town }}`)}</dd> + {btr && `{{` + `/${templateName}.town}}`} + + {btr && `{{` + `#${templateName}.town_location}}`} + <dd> + {location?.town_location || + (btr && `{{ ${templateName}.town_location }}`)} + </dd> + {btr && `{{` + `/${templateName}.town_location}}`} + </Fragment> + ); +} + +export function ShowOrderDetails({ + order_summary, + refund_amount, + contract_terms, + btr, +}: Props): VNode { + const productList = btr + ? [{} as MerchantBackend.Product] + : contract_terms?.products || []; + const auditorsList = btr + ? [{} as MerchantBackend.Auditor] + : contract_terms?.auditors || []; + const exchangesList = btr + ? [{} as MerchantBackend.Exchange] + : contract_terms?.exchanges || []; + const hasDeliveryInfo = + btr || + !!contract_terms?.delivery_date || + !!contract_terms?.delivery_location; + + return ( + <Page> + <header> + <h1> + Details of order{" "} + {contract_terms?.order_id || `{{ contract_terms.order_id }}`} + </h1> + </header> + + <section> + {btr && `{{#refund_amount}}`} + {(btr || refund_amount) && ( + <section> + <InfoBox> + <b>Refunded:</b> The merchant refunded you{" "} + <b>{refund_amount || `{{ refund_amount }}`}</b>. + </InfoBox> + </section> + )} + {btr && `{{/refund_amount}}`} + + <section> + <TableExpanded> + <dt>Order summary:</dt> + <dd>{contract_terms?.summary || `{{ contract_terms.summary }}`}</dd> + <dt>Amount paid:</dt> + <dd>{contract_terms?.amount || `{{ contract_terms.amount }}`}</dd> + <dt>Order date:</dt> + <dd> + {contract_terms?.timestamp + ? contract_terms?.timestamp.t_s != "never" + ? format( + contract_terms?.timestamp.t_s, + "dd MMM yyyy HH:mm:ss" + ) + : "never" + : `{{ contract_terms.timestamp_str }}`}{" "} + </dd> + <dt>Merchant name:</dt> + <dd> + {contract_terms?.merchant.name || + `{{ contract_terms.merchant.name }}`} + </dd> + </TableExpanded> + </section> + + {btr && `{{#contract_terms.hasProducts}}`} + {!productList.length ? null : ( + <section> + <h2>Products purchased</h2> + <TableSimple> + {btr && "{{" + "#contract_terms.products" + "}}"} + {productList.map((p, i) => { + const taxList = btr + ? [{} as MerchantBackend.Tax] + : p.taxes || []; + + return ( + <Fragment key={i}> + <p>{p.description || `{{description}}`}</p> + <dl> + <dt>Quantity:</dt> + <dd>{p.quantity || `{{quantity}}`}</dd> + + <dt>Price:</dt> + <dd>{p.price || `{{price}}`}</dd> + + {btr && `{{#hasTaxes}}`} + {!taxList.length ? null : ( + <Fragment> + {btr && "{{" + "#taxes" + "}}"} + {taxList.map((t, i) => { + return ( + <Fragment key={i}> + <dt>{t.name || `{{name}}`}</dt> + <dd>{t.tax || `{{tax}}`}</dd> + </Fragment> + ); + })} + {btr && "{{" + "/taxes" + "}}"} + </Fragment> + )} + {btr && `{{/hasTaxes}}`} + + {btr && `{{#delivery_date}}`} + {(btr || p.delivery_date) && ( + <Fragment> + <dt>Delivered on:</dt> + <dd> + {p.delivery_date + ? p.delivery_date.t_s != "never" + ? format( + p.delivery_date.t_s, + "dd MMM yyyy HH:mm:ss" + ) + : "never" + : `{{ delivery_date_str }}`}{" "} + </dd> + </Fragment> + )} + {btr && `{{/delivery_date}}`} + + {btr && `{{#unit}}`} + {(btr || p.unit) && ( + <Fragment> + <dt>Product unit:</dt> + <dd>{p.unit || `{{.}}`}</dd> + </Fragment> + )} + {btr && `{{/unit}}`} + + {btr && `{{#product_id}}`} + {(btr || p.product_id) && ( + <Fragment> + <dt>Product ID:</dt> + <dd>{p.product_id || `{{.}}`}</dd> + </Fragment> + )} + {btr && `{{/product_id}}`} + </dl> + </Fragment> + ); + })} + {btr && "{{" + "/contract_terms.products" + "}}"} + </TableSimple> + </section> + )} + {btr && `{{/contract_terms.hasProducts}}`} + + {btr && `{{#contract_terms.has_delivery_info}}`} + {!hasDeliveryInfo ? null : ( + <section> + <h2>Delivery information</h2> + <TableExpanded> + {btr && `{{#contract_terms.delivery_date}}`} + {(btr || contract_terms?.delivery_date) && ( + <Fragment> + <dt>Delivery date:</dt> + <dd> + {contract_terms?.delivery_date + ? contract_terms?.delivery_date.t_s != "never" + ? format( + contract_terms?.delivery_date.t_s, + "dd MMM yyyy HH:mm:ss" + ) + : "never" + : `{{ contract_terms.delivery_date_str }}`}{" "} + </dd> + </Fragment> + )} + {btr && `{{/contract_terms.delivery_date}}`} + + {btr && `{{#contract_terms.delivery_location}}`} + {(btr || contract_terms?.delivery_location) && ( + <Fragment> + <dt>Delivery address:</dt> + <Location + btr={btr} + location={contract_terms?.delivery_location} + templateName="contract_terms.delivery_location" + /> + </Fragment> + )} + {btr && `{{/contract_terms.delivery_location}}`} + </TableExpanded> + </section> + )} + {btr && `{{/contract_terms.has_delivery_info}}`} + + <section> + <h2>Full payment information</h2> + <TableExpanded> + <dt>Amount paid:</dt> + <dd>{contract_terms?.amount || `{{ contract_terms.amount }}`}</dd> + <dt>Wire transfer method:</dt> + <dd> + {contract_terms?.wire_method || + `{{ contract_terms.wire_method }}`} + </dd> + <dt>Payment deadline:</dt> + <dd> + {contract_terms?.pay_deadline + ? contract_terms?.pay_deadline.t_s != "never" + ? format( + contract_terms?.pay_deadline.t_s, + "dd MMM yyyy HH:mm:ss" + ) + : "never" + : `{{ contract_terms.pay_deadline_str }}`}{" "} + </dd> + <dt>Exchange transfer deadline:</dt> + <dd> + {contract_terms?.wire_transfer_deadline + ? contract_terms?.wire_transfer_deadline.t_s != "never" + ? format( + contract_terms?.wire_transfer_deadline.t_s, + "dd MMM yyyy HH:mm:ss" + ) + : "never" + : `{{ contract_terms.wire_transfer_deadline_str }}`}{" "} + </dd> + <dt>Maximum deposit fee:</dt> + <dd>{contract_terms?.max_fee || `{{ contract_terms.max_fee }}`}</dd> + <dt>Maximum wire fee:</dt> + <dd> + {contract_terms?.max_wire_fee || + `{{ contract_terms.max_wire_fee }}`} + </dd> + <dt>Wire fee amortization:</dt> + <dd> + {contract_terms?.wire_fee_amortization || + `{{ contract_terms.wire_fee_amortization }}`}{" "} + transactions + </dd> + </TableExpanded> + </section> + + <section> + <h2>Refund information</h2> + <TableExpanded> + <dt>Refund deadline:</dt> + <dd> + {contract_terms?.refund_deadline + ? contract_terms?.refund_deadline.t_s != "never" + ? format( + contract_terms?.refund_deadline.t_s, + "dd MMM yyyy HH:mm:ss" + ) + : "never" + : `{{ contract_terms.refund_deadline_str }}`}{" "} + </dd> + + {btr && `{{#contract_terms.auto_refund}}`} + {(btr || contract_terms?.auto_refund) && ( + <Fragment> + <dt>Attempt autorefund for:</dt> + <dd> + {contract_terms?.auto_refund + ? contract_terms?.auto_refund.d_us != "forever" + ? formatDuration( + intervalToDuration({ + start: 0, + end: contract_terms?.auto_refund.d_us, + }) + ) + : "forever" + : `{{ contract_terms.auto_refund_str }}`}{" "} + </dd> + </Fragment> + )} + {btr && `{{/contract_terms.auto_refund}}`} + </TableExpanded> + </section> + + <section> + <h2>Additional order details</h2> + <TableExpanded> + <dt>Public reorder URL:</dt> + <dd> -- not defined yet -- </dd> + {btr && `{{#contract_terms.fulfillment_url}}`} + {(btr || contract_terms?.fulfillment_url) && ( + <Fragment> + <dt>Fulfillment URL:</dt> + <dd> + {contract_terms?.fulfillment_url || + (btr && `{{ contract_terms.fulfillment_url }}`)} + </dd> + </Fragment> + )} + {btr && `{{/contract_terms.fulfillment_url}}`} + {/* <dt>Fulfillment message:</dt> + <dd> -- not defined yet -- </dd> */} + </TableExpanded> + </section> + + <section> + <h2>Full merchant information</h2> + <TableExpanded> + <dt>Merchant name:</dt> + <dd> + {contract_terms?.merchant.name || + `{{ contract_terms.merchant.name }}`} + </dd> + <dt>Merchant address:</dt> + <Location + btr={btr} + location={contract_terms?.merchant.address} + templateName="contract_terms.merchant.address" + /> + <dt>Merchant's jurisdiction:</dt> + <Location + btr={btr} + location={contract_terms?.merchant.jurisdiction} + templateName="contract_terms.merchant.jurisdiction" + /> + <dt>Merchant URI:</dt> + <dd> + {contract_terms?.merchant_base_url || + `{{ contract_terms.merchant_base_url }}`} + </dd> + <dt>Merchant's public key:</dt> + <dd> + {contract_terms?.merchant_pub || + `{{ contract_terms.merchant_pub }}`} + </dd> + {/* <dt>Merchant's hash:</dt> + <dd> -- not defined yet -- </dd> */} + </TableExpanded> + </section> + + {btr && `{{#contract_terms.hasAuditors}}`} + {!auditorsList.length ? null : ( + <section> + <h2>Auditors accepted by the merchant</h2> + <TableExpanded> + {btr && "{{" + "#contract_terms.auditors" + "}}"} + {auditorsList.map((p, i) => { + return ( + <Fragment key={i}> + <p>{p.name || `{{name}}`}</p> + <dt>Auditor's public key:</dt> + <dd>{p.auditor_pub || `{{auditor_pub}}`}</dd> + <dt>Auditor's URL:</dt> + <dd>{p.url || `{{url}}`}</dd> + </Fragment> + ); + })} + {btr && "{{" + "/contract_terms.auditors" + "}}"} + </TableExpanded> + </section> + )} + {btr && `{{/contract_terms.hasAuditors}}`} + + {btr && `{{#contract_terms.hasExchanges}}`} + {!exchangesList.length ? null : ( + <section> + <h2>Exchanges accepted by the merchant</h2> + <TableExpanded> + {btr && "{{" + "#contract_terms.exchanges" + "}}"} + {exchangesList.map((p, i) => { + return ( + <Fragment key={i}> + <dt>Exchange's URL:</dt> + <dd>{p.url || `{{url}}`}</dd> + <dt>Public key:</dt> + <dd>{p.master_pub || `{{master_pub}}`}</dd> + </Fragment> + ); + })} + {btr && "{{" + "/contract_terms.exchanges" + "}}"} + </TableExpanded> + </section> + )} + {btr && `{{/contract_terms.hasExchanges}}`} + </section> + + <Footer /> + </Page> + ); +} + +export function mount(): void { + try { + const fromLocation = new URL(window.location.href).searchParams; + const os = fromLocation.get("order_summary") || undefined; + if (os) { + render(<Head order_summary={os} />, document.head); + } + + const ra = fromLocation.get("refund_amount") || undefined; + const ct = fromLocation.get("contract_terms") || undefined; + + let contractTerms: MerchantBackend.ContractTerms | undefined; + try { + contractTerms = JSON.parse((window as any).contractTermsStr); + } catch {} + + render( + <ShowOrderDetails + contract_terms={contractTerms} + order_summary={os} + refund_amount={ra} + />, + document.body + ); + } catch (e) { + console.error("got error", e); + if (e instanceof Error) { + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } + } +} + +export function buildTimeRendering(): { head: string; body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<ShowOrderDetails btr />), + }; +} diff --git a/packages/merchant-backend-ui/src/styled/index.tsx b/packages/merchant-backend-ui/src/styled/index.tsx new file mode 100644 index 000000000..55803b9cd --- /dev/null +++ b/packages/merchant-backend-ui/src/styled/index.tsx @@ -0,0 +1,178 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import { styled } from '@linaria/react' + +export const QRPlaceholder = styled.div` + margin: auto; + text-align: center; + width: 340px; +` + +export const FooterBar = styled.footer` + text-align: center; + background-color: #033; + color: white; + padding: 1em; + overflow: auto; + + & > p > a:link, + & > p > a:visited, + & > p > a:hover, + & > p > a:active { + color: white; + } +` + +export const Page = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; + min-height: 100vh; + align-items: center; + + a:link, + a:visited, + a:hover, + a:active { + color: black; + } + + section { + text-align: center; + width: 600px; + /* margin: auto; */ + /* margin-top: 0px; */ + margin-bottom: auto; + /* overflow: auto; */ + } + section:not(:first-of-type) { + margin-top: 2em; + } + & > header { + display: flex; + flex-direction: row; + justify-content: space-between; + text-align: center; + } + & > footer { + display: flex; + flex-direction: row; + justify-content: space-around; + width: 100%; + margin-bottom: 0px; + } +` +export const Center = styled.div` + display: flex; + justify-content: center; +` + +export const WalletLink = styled.a<{ upperCased?: boolean }>` + display: inline-block; + zoom: 1; + line-height: normal; + white-space: nowrap; + vertical-align: middle; + text-align: center; + cursor: pointer; + user-select: none; + box-sizing: border-box; + text-transform: ${({ upperCased }) => upperCased ? 'uppercase' : 'none'}; + + font-family: inherit; + font-size: 100%; + padding: 0.5em 1em; + color: #444; /* rgba not supported (IE 8) */ + color: rgba(0, 0, 0, 0.8); /* rgba supported */ + border: 1px solid #999; /*IE 6/7/8*/ + border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/ + background-color: '#e6e6e6'; + text-decoration: none; + border-radius: 2px; + + :focus { + outline: 0; + } + + &:disabled { + border: none; + background-image: none; + /* csslint ignore:start */ + filter: alpha(opacity=40); + /* csslint ignore:end */ + opacity: 0.4; + cursor: not-allowed; + box-shadow: none; + pointer-events: none; + } + + :hover { + filter: alpha(opacity=90); + background-image: linear-gradient( + transparent, + rgba(0, 0, 0, 0.05) 40%, + rgba(0, 0, 0, 0.1) + ); + } + + background-color: #e6e6e6; + border-radius: 4px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, + 0 0 6px rgba(0, 0, 0, 0.2) inset; + border-color: #000; +`; + +export const InfoBox = styled.div` + border-radius: 0.25em; + flex-direction: column; + /* margin: 0.5em; */ + padding: 1em; + /* width: 100%; */ + border:solid 1px #b8daff; + background-color:#cce5ff; + color:#004085; +` + +export const TableExpanded = styled.dl` + text-align: left; + dt { + font-weight: bold; + margin-top: 1em; + } + dd { + margin-inline-start: 0px; + } +` + +export const TableSimple = styled.dl` + text-align: left; + dt { + font-weight: bold; + display: inline-block; + width:30%; + } + dd { + margin-inline-start: 0px; + display: inline-block; + width:70%; + } +`
\ No newline at end of file diff --git a/packages/merchant-backend-ui/src/utils/amount.ts b/packages/merchant-backend-ui/src/utils/amount.ts new file mode 100644 index 000000000..85f230427 --- /dev/null +++ b/packages/merchant-backend-ui/src/utils/amount.ts @@ -0,0 +1,69 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { amountFractionalBase, AmountJson, Amounts } from "@gnu-taler/taler-util"; +import { MerchantBackend } from "../declaration"; + +/** + * sums two prices, + * @param one + * @param two + * @returns + */ +const sumPrices = (one: string, two: string) => { + const [currency, valueOne] = one.split(':') + const [, valueTwo] = two.split(':') + return `${currency}:${parseInt(valueOne, 10) + parseInt(valueTwo, 10)}` +} + +/** + * merge refund with the same description and a difference less than one minute + * @param prev list of refunds that will hold the merged refunds + * @param cur new refund to add to the list + * @returns list with the new refund, may be merged with the last + */ +export function mergeRefunds(prev: MerchantBackend.Orders.RefundDetails[], cur: MerchantBackend.Orders.RefundDetails) { + let tail; + + if (prev.length === 0 || //empty list + cur.timestamp.t_s === 'never' || //current doesnt have timestamp + (tail = prev[prev.length - 1]).timestamp.t_s === 'never' || // last doesnt have timestamp + cur.reason !== tail.reason || //different reason + Math.abs(cur.timestamp.t_s - tail.timestamp.t_s) > 1000 * 60) {//more than 1 minute difference + + prev.push(cur) + return prev + } + + prev[prev.length - 1] = { + ...tail, + amount: sumPrices(tail.amount, cur.amount) + } + + return prev +} + +export const rate = (one: string, two: string) => { + const a = Amounts.parseOrThrow(one) + const b = Amounts.parseOrThrow(two) + const af = toFloat(a) + const bf = toFloat(b) + if (bf === 0) return 0 + return af / bf +} + +function toFloat(amount: AmountJson) { + return amount.value + (amount.fraction / amountFractionalBase); +} diff --git a/packages/merchant-backend-ui/src/utils/constants.ts b/packages/merchant-backend-ui/src/utils/constants.ts new file mode 100644 index 000000000..37c46e4c2 --- /dev/null +++ b/packages/merchant-backend-ui/src/utils/constants.ts @@ -0,0 +1,47 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +//https://tools.ietf.org/html/rfc8905 +export const PAYTO_REGEX = /^payto:\/\/[a-zA-Z][a-zA-Z0-9-.]+(\/[a-zA-Z0-9\-\.\~\(\)@_%:!$&'*+,;=]*)*\??((amount|receiver-name|sender-name|instruction|message)=[a-zA-Z0-9\-\.\~\(\)@_%:!$'*+,;=]*&?)*$/ +export const PAYTO_WIRE_METHOD_LOOKUP = /payto:\/\/([a-zA-Z][a-zA-Z0-9-.]+)\/.*/ + +export const AMOUNT_REGEX = /^[a-zA-Z][a-zA-Z]*:[0-9][0-9,]*\.?[0-9,]*$/ + +export const INSTANCE_ID_LOOKUP = /^\/instances\/([^/]*)\/?$/ + +export const AMOUNT_ZERO_REGEX = /^[a-zA-Z][a-zA-Z]*:0$/ + +export const CROCKFORD_BASE32_REGEX = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]+[*~$=U]*$/ + +export const URL_REGEX = /^((https?:)(\/\/\/?)([\w]*(?::[\w]*)?@)?([\d\w\.-]+)(?::(\d+))?)\/$/ + +// how much rows we add every time user hit load more +export const PAGE_SIZE = 20 +// how bigger can be the result set +// after this threshold, load more with move the cursor +export const MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1; + +// how much we will wait for all request, in seconds +export const DEFAULT_REQUEST_TIMEOUT = 10; + +export const MAX_IMAGE_SIZE = 1024 * 1024; + +export const INSTANCE_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.@-]+$/ diff --git a/packages/merchant-backend-ui/src/utils/table.ts b/packages/merchant-backend-ui/src/utils/table.ts new file mode 100644 index 000000000..3d713a6f7 --- /dev/null +++ b/packages/merchant-backend-ui/src/utils/table.ts @@ -0,0 +1,37 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { WithId } from "../declaration"; + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +export interface Actions<T extends WithId> { + element: T; + type: 'DELETE' | 'UPDATE'; +} + +function notEmpty<TValue>(value: TValue | null | undefined): value is TValue { + return value !== null && value !== undefined; +} + +export function buildActions<T extends WithId>(intances: T[], selected: string[], action: 'DELETE'): Actions<T>[] { + return selected.map(id => intances.find(i => i.id === id)) + .filter(notEmpty) + .map(id => ({ element: id, type: action })) +} diff --git a/packages/merchant-backend-ui/src/utils/types.ts b/packages/merchant-backend-ui/src/utils/types.ts new file mode 100644 index 000000000..9e49d39e1 --- /dev/null +++ b/packages/merchant-backend-ui/src/utils/types.ts @@ -0,0 +1,31 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { VNode } from "preact" + +export interface KeyValue { + [key: string]: string; +} + +export interface Notification { + message: string; + description?: string | VNode; + type: MessageType; +} + +export type ValueOrFunction<T> = T | ((p: T) => T) +export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS' + diff --git a/packages/merchant-backend-ui/tests/__mocks__/browserMocks.ts b/packages/merchant-backend-ui/tests/__mocks__/browserMocks.ts new file mode 100644 index 000000000..ee6bba505 --- /dev/null +++ b/packages/merchant-backend-ui/tests/__mocks__/browserMocks.ts @@ -0,0 +1,42 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + /** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +// Mock Browser API's which are not supported by JSDOM, e.g. ServiceWorker, LocalStorage +/** + * An example how to mock localStorage is given below π + */ + +/* +// Mocks localStorage +const localStorageMock = (function() { + let store = {}; + + return { + getItem: (key) => store[key] || null, + setItem: (key, value) => store[key] = value.toString(), + clear: () => store = {} + }; + +})(); + +Object.defineProperty(window, 'localStorage', { + value: localStorageMock +}); */ diff --git a/packages/merchant-backend-ui/tests/__mocks__/fileMocks.ts b/packages/merchant-backend-ui/tests/__mocks__/fileMocks.ts new file mode 100644 index 000000000..0c045e9d1 --- /dev/null +++ b/packages/merchant-backend-ui/tests/__mocks__/fileMocks.ts @@ -0,0 +1,24 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + /** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +// This fixed an error related to the CSS and loading gif breaking my Jest test +// See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets +export default 'test-file-stub'; diff --git a/packages/merchant-backend-ui/tests/__mocks__/fileTransformer.js b/packages/merchant-backend-ui/tests/__mocks__/fileTransformer.js new file mode 100644 index 000000000..51ebbfa62 --- /dev/null +++ b/packages/merchant-backend-ui/tests/__mocks__/fileTransformer.js @@ -0,0 +1,31 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +// fileTransformer.js + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const path = require('path'); + +module.exports = { + process(src, filename, config, options) { + return `module.exports = ${ JSON.stringify(path.basename(filename)) };`; + }, +}; + diff --git a/packages/merchant-backend-ui/tests/__mocks__/setupTests.ts b/packages/merchant-backend-ui/tests/__mocks__/setupTests.ts new file mode 100644 index 000000000..ab0f08b2f --- /dev/null +++ b/packages/merchant-backend-ui/tests/__mocks__/setupTests.ts @@ -0,0 +1,28 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + /** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import 'regenerator-runtime/runtime' +import { configure } from 'enzyme'; +import Adapter from 'enzyme-adapter-preact-pure'; + +configure({ + adapter: new Adapter() +}); diff --git a/packages/merchant-backend-ui/tests/funcitons/regex.test.ts b/packages/merchant-backend-ui/tests/funcitons/regex.test.ts new file mode 100644 index 000000000..fc8a6a42f --- /dev/null +++ b/packages/merchant-backend-ui/tests/funcitons/regex.test.ts @@ -0,0 +1,87 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + + /** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { AMOUNT_REGEX, PAYTO_REGEX } from "../../src/utils/constants"; + +describe('payto uri format', () => { + const valids = [ + 'payto://iban/DE75512108001245126199?amount=EUR:200.0&message=hello', + 'payto://ach/122000661/1234', + 'payto://upi/alice@example.com?receiver-name=Alice&amount=INR:200', + 'payto://void/?amount=EUR:10.5', + 'payto://ilp/g.acme.bob' + ] + + test('should be valid', () => { + valids.forEach(v => expect(v).toMatch(PAYTO_REGEX)) + }); + + const invalids = [ + // has two question marks + 'payto://iban/DE75?512108001245126199?amount=EUR:200.0&message=hello', + // has a space + 'payto://ach /122000661/1234', + // has a space + 'payto://upi/alice@ example.com?receiver-name=Alice&amount=INR:200', + // invalid field name (mount instead of amount) + 'payto://void/?mount=EUR:10.5', + // payto:// is incomplete + 'payto: //ilp/g.acme.bob' + ] + + test('should not be valid', () => { + invalids.forEach(v => expect(v).not.toMatch(PAYTO_REGEX)) + }); +}) + +describe('amount format', () => { + const valids = [ + 'ARS:10', + 'COL:10.2', + 'UY:1,000.2', + 'ARS:10.123,123', + 'ARS:1,000,000', + 'ARSCOL:10', + 'THISISTHEMOTHERCOIN:1,000,000.123,123', + ] + + test('should be valid', () => { + valids.forEach(v => expect(v).toMatch(AMOUNT_REGEX)) + }); + + const invalids = [ + //no currency name + ':10', + //use . instead of , + 'ARS:1.000.000', + //currency name with numbers + '1ARS:10', + //currency name with numbers + 'AR5:10', + //missing value + 'USD:', + ] + + test('should not be valid', () => { + invalids.forEach(v => expect(v).not.toMatch(AMOUNT_REGEX)) + }); + +})
\ No newline at end of file diff --git a/packages/merchant-backend-ui/tests/util.ts b/packages/merchant-backend-ui/tests/util.ts new file mode 100644 index 000000000..14b82b51c --- /dev/null +++ b/packages/merchant-backend-ui/tests/util.ts @@ -0,0 +1,62 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ +import * as axios from 'axios'; + +type Query<Req, Res> = (GetQuery | PostQuery | DeleteQuery | PatchQuery) & RequestResponse<Req, Res> + +interface RequestResponse<Req, Res> { + request?: Req, + params?: any, + response?: Res, +} +interface GetQuery { get: string } +interface PostQuery { post: string } +interface DeleteQuery { delete: string } +interface PatchQuery { patch: string } + +export function simulateBackendResponse<R, T>(query: Query<R, T>): void { + (axios.default as jest.MockedFunction<axios.AxiosStatic>).mockImplementationOnce(function (opt?: axios.AxiosRequestConfig): axios.AxiosPromise { + // console.log(opt, JSON.stringify(query,undefined,2)) + expect(opt).toBeDefined(); + if (!opt) + return Promise.reject(); + + // expect(query.request).toStrictEqual(opt.data); + // expect(query.params).toStrictEqual(opt.params); + if ('get' in query) { + expect(opt.method).toBe('get'); + expect(opt.url).toBe(query.get); + } + if ('post' in query) { + expect(opt.method).toBe('post'); + expect(opt.url).toBe(query.post); + } + if ('delete' in query) { + expect(opt.method).toBe('delete'); + expect(opt.url).toBe(query.delete); + } + if ('patch' in query) { + expect(opt.method).toBe('patch'); + expect(opt.url).toBe(query.patch); + } + return ({ data: query.response, config: {} } as any); + } as any) +} diff --git a/packages/merchant-backend-ui/tsconfig.back.json b/packages/merchant-backend-ui/tsconfig.back.json new file mode 100644 index 000000000..9ac5a3c25 --- /dev/null +++ b/packages/merchant-backend-ui/tsconfig.back.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "composite": true, + "lib": ["es6", "DOM"], + "jsx": "react", + "jsxFactory": "h", + "jsxFragmentFactory": "Fragment", + "moduleResolution": "Node", + "module": "ESNext", + "target": "ES6", + "noImplicitAny": true, + "noEmitOnError": true, + "strict": true, + "incremental": true, + "sourceMap": true, + "esModuleInterop": true, + "importHelpers": true, + "rootDir": "./src", + "typeRoots": ["./node_modules/@types"] + }, + "include": ["src/**/*"] + } +
\ No newline at end of file diff --git a/packages/merchant-backend-ui/tsconfig.json b/packages/merchant-backend-ui/tsconfig.json new file mode 100644 index 000000000..7a4d70a17 --- /dev/null +++ b/packages/merchant-backend-ui/tsconfig.json @@ -0,0 +1,61 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ + "module": "ESNext", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation: */ + "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "jsxFactory": "h", /* Specify the JSX factory function to use when targeting react JSX emit, e.g. React.createElement or h. */ + "jsxFragmentFactory": "Fragment", // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#custom-jsx-factories + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "removeComments": true, /* Do not emit comments to output. */ + "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "esModuleInterop": true, /* */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */ + }, + "include": ["src/**/*", "tests/**/*"] +} |