repo: integrate packages from former merchant-backoffice.git

This commit is contained in:
Florian Dold 2022-10-24 10:46:14 +02:00
parent fb52ced35a
commit 3e060b8042
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
402 changed files with 78581 additions and 782 deletions

5
packages/demobank-ui/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
node_modules
/build
/*.log
/size-plugin.json
/storybook-static/

View File

@ -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"
]
}

View File

@ -0,0 +1,57 @@
/*
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'
],
],
}),
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",
};
return config;
},
}

View File

@ -0,0 +1,55 @@
/*
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 "../src/scss/main.scss"
import { TranslationProvider } from '../src/context/translation'
import { h } from 'preact';
export const parameters = {
controls: { expanded: true },
options: {
storySort: (a, b) => {
return (a[1].args.order ?? 0) - (b[1].args.order ?? 0)
// return a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, { numeric: true })
}
},
}
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 }) => {
document.body.parentElement.classList = "has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded"
return <Story />
},
(Story, { globals }) => <TranslationProvider initial='en' forceLang={globals.locale}>
<Story />
</TranslationProvider>,
];

View File

@ -0,0 +1,19 @@
# bank web
## CLI Commands
- `npm install`: Installs dependencies
- `npm run dev`: Run a development, HMR server
- `npm run serve`: Run a production-like server
- `npm run build`: Production-ready build
- `npm run lint`: Pass TypeScript files using ESLint
- `npm run test`: Run Jest and Enzyme with
[`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure) for
your tests
For detailed explanation on how things work, checkout the [CLI Readme](https://github.com/developit/preact-cli/blob/master/README.md).

45
packages/demobank-ui/TODO Normal file
View File

@ -0,0 +1,45 @@
Urgent TODOs:
- General:
* not only Nora dark-theme, but default light! (CSS)
* auto-focus on input fields is not working well
* buttons should be visibly insensitive
as long as required input fields are not
working
* next required invalid/missing input field is
not properly highlighted in red
* Logout button needs more padding to the right (CSS)
- Error bar:
* shows JSON, should only show good error message
and numeric code, not JSON syntax
* should auto-hide after next action, no need for
"clear"!
* need variant "status bar" in green (or blue)
which shows status of last operation
* H1-Titles:
* Center more (currently way on the left) (CSS)
- Assets:
* Numeric amount needs to be shown MUCH bigger (CSS)
* Center more? (CSS)
- Payments:
* Amount to withdraw currently shown in white-on-white (CSS)
* Big frame drawn around notebook-tabs is not nice (CSS)
* Center more? (CSS)
* "Wire to bank account"
- maybe split two types (payto and IBAN) into
two tabs?
- currently cannot switch back from payto to IBAN
- Withdraw:
* Should use new 'status' bar at the end, instead
of extra dialog with "close" button
* ditto for bank-wire-transfer final stage
- Footer:
* overlaps with transaction history or other
content, needs to consistently show at the
end! => change rendering logic!? (CSS?)

View File

@ -0,0 +1,32 @@
#!/bin/bash
set -eu
# NOTE: the <Translate> node somehow didn't get
# the strings extracted. Only i18n`` did
function build {
POTGEN=node_modules/@gnu-taler/pogen/bin/pogen
PACKAGE_NAME=$1
find src/ \( -type f -name "*.ts" -or -name "*.tsx" \) ! -name "*.d.ts" \
| xargs node $POTGEN \
| msguniq \
| msgmerge src/i18n/poheader - \
> src/i18n/$PACKAGE_NAME.pot
# merge existing translations: fails when NO .po-files were found.
for pofile in $(ls src/i18n/*.po 2> /dev/null || true); do
echo merging $pofile;
msgmerge -o $pofile $pofile src/i18n/$PACKAGE_NAME.pot;
done;
# generate .ts file containing all translations
cat src/i18n/strings-prelude > src/i18n/strings.ts
for pofile in $(ls src/i18n/*.po 2> /dev/null || true); do \
echo appending $pofile; \
./contrib/po2ts $pofile >> src/i18n/strings.ts; \
done;
}
build bank

View File

@ -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);

View File

@ -0,0 +1,4 @@
{
"register": {},
"transactions": {}
}

View File

@ -0,0 +1,27 @@
Object.defineProperty(window, 'requestAnimationFrame', {
value: function(cb) {} // Silence the browser.
})
Object.defineProperty(window, 'localStorage', {
value: {
store: {},
getItem: function(key) {
return this.store[key];
},
setItem: function(key, value) {
return this.store[key] = value;
},
clear: function() {
this.store = {};
}
}
});
Object.defineProperty(window, 'location', {
value: {
origin: "http://localhost:8080", /* where taler-local rev proxy listens to */
search: "",
pathname: "/sandbox/demobanks/default",
}
})
export default window;

View File

@ -0,0 +1,100 @@
{
"private": true,
"name": "bank",
"version": "0.1.0",
"license": "AGPL-3.0-OR-LATER",
"scripts": {
"dev": "preact watch --port ${PORT:=9090} --no-sw --no-esm -c preact.mock.js",
"build": "preact build --no-sw --no-esm -c preact.single-config.js --dest build && sh remove-link-stylesheet.sh",
"serve": "sirv build --port ${PORT:=8080} --cors --single",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"test": "jest ./tests",
"build-storybook": "build-storybook",
"serve-single": "sirv single --port ${PORT:=8080} --cors --single",
"pretty": "prettier --write src",
"storybook": "start-storybook -p 6006"
},
"eslintConfig": {
"parser": "@typescript-eslint/parser",
"extends": [
"preact",
"plugin:@typescript-eslint/recommended"
],
"ignorePatterns": [
"build/"
],
"rules": {
"@typescript-eslint/no-explicit-any": [0],
"@typescript-eslint/ban-ts-comment": [1],
"quotes": [2, "single", {"allowTemplateLiterals": true,"avoidEscape": false}],
"indent": [2,2],
"prefer-arrow-callback": [2, {"allowNamedFunctions": false, "allowUnboundThis": true}],
"curly": [2,"multi"],
"prefer-template": [1]
}
},
"dependencies": {
"base64-inline-loader": "1.1.1",
"date-fns": "2.25.0",
"jed": "1.1.1",
"preact": "^10.5.15",
"preact-render-to-string": "^5.1.19",
"preact-router": "^3.2.1",
"qrcode-generator": "^1.4.4",
"swr": "1.1"
},
"devDependencies": {
"@babel/core": "^7.13.16",
"@babel/plugin-transform-react-jsx": "^7.12.13",
"@babel/plugin-transform-react-jsx-source": "^7.12.13",
"@babel/preset-env": "^7.16.7",
"@creativebulma/bulma-tooltip": "^1.2.0",
"@gnu-taler/pogen": "^0.0.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/jest-dom": "^5.16.1",
"@testing-library/preact": "^2.0.1",
"@testing-library/preact-hooks": "^1.1.0",
"@types/enzyme": "^3.10.10",
"@types/jest": "^27.0.2",
"@typescript-eslint/eslint-plugin": "^5.3.0",
"@typescript-eslint/parser": "^5.3.0",
"babel-loader": "^8.2.2",
"base64-inline-loader": "^1.1.1",
"bulma": "^0.9.3",
"bulma-checkbox": "^1.1.1",
"bulma-radio": "^1.1.1",
"enzyme": "^3.11.0",
"enzyme-adapter-preact-pure": "^3.2.0",
"eslint": "^8.1.0",
"eslint-config-preact": "^1.2.0",
"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": "^27.3.1",
"jest-fetch-mock": "^3.0.3",
"jest-preset-preact": "^4.0.5",
"jest-watch-typeahead": "^1.0.0",
"jest-environment-jsdom": "^27.4.6",
"jssha": "^3.2.0",
"po2json": "^0.4.5",
"preact-cli": "3.0.5",
"sass": "1.32.13",
"sass-loader": "^10",
"script-ext-html-webpack-plugin": "^2.1.5",
"sirv-cli": "^1.0.14",
"typescript": "^4.4.4"
},
"jest": {
"preset": "jest-preset-preact",
"setupFiles": [
"<rootDir>/tests/__mocks__/browserMocks.ts",
"<rootDir>/tests/__mocks__/setupTests.ts"
]
}
}

View File

@ -0,0 +1,70 @@
/*
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 { DefinePlugin } from 'webpack';
import pack from './package.json';
import * as cp from 'child_process';
const commitHash = cp.execSync('git rev-parse --short HEAD').toString();
export default {
webpack(config, env, helpers) {
// ensure that process.env will not be undefined on runtime
config.node.process = 'mock'
// add __VERSION__ to be use in the html
config.plugins.push(
new DefinePlugin({
'process.env.__VERSION__': JSON.stringify(env.isProd ? pack.version : `dev-${commitHash}`) ,
}),
);
// suddenly getting out of memory error from build process, error below [1]
// FIXME: remove preact-cli, use rollup
let { index } = helpers.getPluginsByName(config, 'WebpackFixStyleOnlyEntriesPlugin')[0]
config.plugins.splice(index, 1)
}
}
/* [1] from this error decided to remove plugin 'webpack-fix-style-only-entries
leaving this error for future reference
<--- Last few GCs --->
[32479:0x2e01870] 19969 ms: Mark-sweep 1869.4 (1950.2) -> 1443.1 (1504.1) MB, 497.5 / 0.0 ms (average mu = 0.631, current mu = 0.455) allocation failure scavenge might not succeed
[32479:0x2e01870] 21907 ms: Mark-sweep 2016.9 (2077.9) -> 1628.6 (1681.4) MB, 1596.0 / 0.0 ms (average mu = 0.354, current mu = 0.176) allocation failure scavenge might not succeed
<--- JS stacktrace --->
==== JS stack trace =========================================
0: ExitFrame [pc: 0x13cf099]
Security context: 0x2f4ca66c08d1 <JSObject>
1: /* anonymous * / [0x35d05555b4b9] [...path/merchant-backoffice/node_modules/.pnpm/webpack-fix-style-only-entries@0.5.2/node_modules/webpack-fix-style-only-entries/index.js:~80] [pc=0x2145e699d1a4](this=0x1149465410e9 <GlobalObject Object map = 0xff481b5b5f9>,0x047e52e36a49 <Dependency map = 0x1ed1fe41cd19>)
2: arguments adaptor frame: 3...
FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
*/

View File

@ -0,0 +1,55 @@
/*
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 { DefinePlugin, ProvidePlugin } from 'webpack';
import pack from './package.json';
import * as cp from 'child_process';
const commitHash = cp.execSync('git rev-parse --short HEAD').toString();
import path from 'path';
export default {
webpack(config, env, helpers) {
// Ensure that process.env will not be undefined at runtime.
config.node.process = 'mock'
let DEMO_SITES = {
"Blog": process.env.TALER_ENV_URL_MERCHANT_BLOG,
"Donations": process.env.TALER_ENV_URL_MERCHANT_DONATIONS,
"Survey": process.env.TALER_ENV_URL_MERCHANT_SURVEY,
"Landing": process.env.TALER_ENV_URL_INTRO,
"Bank": process.env.TALER_ENV_URL_BANK,
}
console.log("demo links found", DEMO_SITES);
// Add __VERSION__ to be use in the html.
config.plugins.push(
new DefinePlugin({
'process.env.__VERSION__': JSON.stringify(env.isProd ? pack.version : `dev-${commitHash}`) ,
}),
// 'window' gets mocked to point at a running euFin instance.
new ProvidePlugin({window: path.resolve("mocks/window")}),
new DefinePlugin({"DEMO_SITES": JSON.stringify(DEMO_SITES)})
);
let { index } = helpers.getPluginsByName(config, 'WebpackFixStyleOnlyEntriesPlugin')[0]
config.plugins.splice(index, 1)
}
}

View File

@ -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 defaultConfig from './preact.config'
export default {
webpack(config, env, helpers, options) {
defaultConfig.webpack(config, env, helpers, options)
//1. check no file is under /routers or /component/{routers,async} to prevent async components
// https://github.com/preactjs/preact-cli#route-based-code-splitting
//2. remove devtools to prevent sourcemaps
config.devtool = false
//3. change assetLoader to load assets inline
const loaders = helpers.getLoaders(config)
const assetsLoader = loaders.find(lo => lo.rule.test.test('something.woff'))
if (assetsLoader) {
assetsLoader.rule.use = 'base64-inline-loader'
assetsLoader.rule.loader = undefined
}
//4. remove critters
//critters remove the css bundle from htmlWebpackPlugin.files.css
//for now, pushing all the content into the html is enough
const crittersWrapper = helpers.getPluginsByName(config, 'Critters')
if (crittersWrapper && crittersWrapper.length > 0) {
const [{ index }] = crittersWrapper
config.plugins.splice(index, 1)
}
//5. remove favicon from src/assets
//6. remove performance hints since we now that this is going to be big
if (config.performance) {
config.performance.hints = false
}
//7. template.html should have a favicon and add js/css content
}
}

View File

@ -0,0 +1,8 @@
# This script has been placed in the public domain.
FILE=$(ls build/bundle.*.css)
BUNDLE=${FILE#build}
grep -q '<link href="'$BUNDLE'" rel="stylesheet">' build/index.html || { echo bundle $BUNDLE not found in index.html; exit 1; }
echo -n Removing link from index.html ...
sed 's_<link href="'$BUNDLE'" rel="stylesheet">__' -i build/index.html
echo done

View File

@ -0,0 +1,3 @@
{
"presets": ["preact-cli/babel"]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0l-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z"/></svg>

After

Width:  |  Height:  |  Size: 274 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 15h2v2h-2zM17 11h2v2h-2zM17 7h2v2h-2zM13.74 7l1.26.84V7z"/><path d="M10 3v1.51l2 1.33V5h9v14h-4v2h6V3z"/><path d="M8.17 5.7L15 10.25V21H1V10.48L8.17 5.7zM10 19h3v-7.84L8.17 8.09 3 11.38V19h3v-6h4v6z"/></svg>

After

Width:  |  Height:  |  Size: 359 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 23.59v-3.6c-5.01-.26-9-4.42-9-9.49C2 5.26 6.26 1 11.5 1S21 5.26 21 10.5c0 4.95-3.44 9.93-8.57 12.4l-1.43.69zM11.5 3C7.36 3 4 6.36 4 10.5S7.36 18 11.5 18H13v2.3c3.64-2.3 6-6.08 6-9.8C19 6.36 15.64 3 11.5 3zm-1 11.5h2v2h-2zm2-1.5h-2c0-3.25 3-3 3-5 0-1.1-.9-2-2-2s-2 .9-2 2h-2c0-2.21 1.79-4 4-4s4 1.79 4 4c0 2.5-3 2.75-3 5z"/></svg>

After

Width:  |  Height:  |  Size: 483 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17 1.01L7 1c-1.1 0-1.99.9-1.99 2v18c0 1.1.89 2 1.99 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/></svg>

After

Width:  |  Height:  |  Size: 272 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M18,10.48V6c0-1.1-0.9-2-2-2H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-4.48l4,3.98v-11L18,10.48z M16,9.69V18H4V6h12V9.69z"/><circle cx="10" cy="10" r="2"/><path d="M14,15.43c0-0.81-0.48-1.53-1.22-1.85C11.93,13.21,10.99,13,10,13c-0.99,0-1.93,0.21-2.78,0.58C6.48,13.9,6,14.62,6,15.43 V16h8V15.43z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -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>

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="670"
height="300"
viewBox="0 0 201 90"
version="1.1"
id="svg8">
<g
id="logo">
<g
id="circles"
style="fill:#FFF;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.327943">
<path
d="m 86.662153,1.1211936 c 15.589697,0 29.129227,9.4011664 35.961027,23.2018054 h -5.81736 C 110.4866,13.623304 99.349002,6.5180852 86.662153,6.5180852 c -19.690571,0 -35.652876,17.1120008 -35.652876,38.2205688 0,10.331797 3.825597,19.704678 10.03957,26.582945 -1.342357,1.120912 -2.771532,2.127905 -4.275488,3.006754 C 50.071485,66.553412 45.974857,56.15992 45.974857,44.738654 c 0,-24.089211 18.216325,-43.6174604 40.687296,-43.6174604 z M 122.51416,65.375898 c -6.86645,13.680134 -20.34561,22.980218 -35.852007,22.980218 -1.052702,0 -2.096093,-0.04291 -3.128683,-0.127026 3.052192,-1.561167 5.913582,-3.480387 8.538307,-5.707305 10.320963,-1.684389 19.185983,-8.113638 24.601813,-17.145887 z"
id="path2350" />
<path
d="m 64.212372,1.1211936 c 1.052607,0 2.095998,0.042919 3.128684,0.1270583 C 64.288864,2.8094199 61.427378,4.728606 58.802653,6.9555572 41.679542,9.7498571 28.559494,25.601563 28.559494,44.738654 c 0,14.264563 7.29059,26.702023 18.093843,33.268925 -1.593656,0.26719 -3.226966,0.406948 -4.890748,0.406948 -1.239545,0 -2.46151,-0.07952 -3.663522,-0.229364 C 29.191129,70.184015 23.525076,58.171633 23.525076,44.738654 23.525076,20.649443 41.7414,1.1211936 64.212372,1.1211936 Z M 69.62209,82.521785 C 79.943207,80.837396 88.808164,74.407841 94.224059,65.375422 h 5.840511 c -6.866354,13.680305 -20.345548,22.980694 -35.852198,22.980694 -1.052703,0 -2.095999,-0.04291 -3.128684,-0.127026 3.052002,-1.561371 5.913836,-3.480218 8.538402,-5.707305 z M 94.355885,24.322999 c -3.13939,-5.314721 -7.467551,-9.74275 -12.584511,-12.853269 1.593656,-0.26719 3.226904,-0.406948 4.890779,-0.406948 1.239451,0 2.461512,0.07952 3.663524,0.229364 4.016018,3.607242 7.373195,8.030111 9.849053,13.030853 z"
id="path2352" />
<path
d="m 41.762589,1.1211936 c 1.064296,0 2.118804,0.044379 3.162607,0.1302161 -3.046523,1.558961 -5.903162,3.4745139 -8.52358,5.6968133 C 19.254624,9.7205882 6.1097128,25.583465 6.1097128,44.738654 c 0,21.108568 15.9624012,38.22057 35.6528762,38.22057 12.599746,0 23.672446,-7.007056 30.013748,-17.583802 h 5.838515 C 70.748498,79.055727 57.26924,88.356116 41.762589,88.356116 c -22.470907,0 -40.6871998,-19.52825 -40.6871998,-43.617462 0,-24.089211 18.2162928,-43.6174604 40.6871998,-43.6174604 z M 71.905375,24.322999 c -1.31192,-2.220567 -2.830984,-4.287049 -4.528877,-6.166508 1.342452,-1.120945 2.771374,-2.128381 4.275139,-3.00723 2.372984,2.753011 4.418875,5.834636 6.072489,9.173738 z"
id="path2354" />
</g>
<g
id="letters"
style="fill:#FFF">
<path
d="m 76.135411,34.409066 h 9.161042 V 29.36588 H 61.857537 v 5.043186 h 9.161137 v 25.92317 h 5.116737 z"
id="path2346" />
<path
d="m 92.647571,52.856334 h 13.659009 l 2.93009,7.476072 h 5.36461 L 101.89122,29.144903 H 97.187186 L 84.477089,60.332406 h 5.199533 z m 11.802109,-4.822276 h -9.944771 l 4.951718,-12.386462 z"
id="path2362" />
<path
d="m 123.80641,29.366084 h -4.58038 v 30.966322 h 20.54728 v -4.910253 c -5.32227,0 -10.64463,0 -15.9669,0 z"
id="path2356" />
<path
d="m 166.4722,29.366084 h -21.37564 v 30.966322 h 21.58203 v -4.910253 h -16.54771 v -8.27275 h 14.48439 V 42.23925 h -14.48439 v -7.962811 h 16.34132 z"
id="path2360" />
<path
d="m 191.19035,39.474593 c 0,1.59947 -0.53646,2.87535 -1.61628,3.818883 -1.07281,0.95124 -2.52409,1.422837 -4.34678,1.422837 h -7.44851 V 34.276439 h 7.4073 c 1.9051,0 3.38376,0.435027 4.42939,1.312178 1.05226,0.870258 1.57488,2.167734 1.57488,3.885976 z m 6.06602,20.857813 -7.79911,-11.723191 c 1.01771,-0.294794 1.94631,-0.714813 2.78553,-1.260566 0.83885,-0.545619 1.56122,-1.209263 2.16629,-1.990627 0.60541,-0.781738 1.07981,-1.681096 1.42369,-2.698345 0.34378,-1.017553 0.51561,-2.175238 0.51561,-3.472883 0,-1.50409 -0.24743,-2.867948 -0.74267,-4.092048 -0.49515,-1.223794 -1.20344,-2.256186 -2.12499,-3.096734 -0.92173,-0.840446 -2.04957,-1.489252 -3.38375,-1.946452 -1.33447,-0.457267 -2.82692,-0.685476 -4.4774,-0.685476 h -12.87512 v 30.966322 h 5.03433 V 49.538522 h 6.37569 l 7.11829,10.793884 z"
id="path2358" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -0,0 +1,66 @@
/*
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 { ComponentChildren, h, VNode } from 'preact';
import { useLayoutEffect, useRef } from 'preact/hooks';
// import { LoadingModal } from "../modal";
import { useAsync } from '../hooks/async';
// import { Translate } from "../../i18n";
type Props = {
children: ComponentChildren;
disabled?: boolean;
onClick?: () => Promise<void>;
grabFocus?: boolean;
[rest: string]: any;
};
export function AsyncButton({
onClick,
grabFocus,
disabled,
children,
...rest
}: Props): VNode {
const { isLoading, request } = useAsync(onClick);
const buttonRef = useRef<HTMLButtonElement>(null);
useLayoutEffect(() => {
if (grabFocus)
buttonRef.current?.focus();
}, [grabFocus]);
// if (isSlow) {
// return <LoadingModal onCancel={cancel} />;
// }
if (isLoading)
return <button class="button">Loading...</button>;
return (
<span data-tooltip={rest['data-tooltip']} style={{ marginLeft: 5 }}>
<button {...rest} ref={buttonRef} onClick={request} disabled={disabled}>
{children}
</button>
</span>
);
}

View File

@ -0,0 +1,57 @@
import { h, VNode } from 'preact';
import { useRef, useState } from 'preact/hooks';
const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
export interface FileTypeContent {
content: string;
type: string;
name: string;
}
interface Props {
label: string;
onChange: (v: FileTypeContent | undefined) => void;
}
export function FileButton(props: Props): VNode {
const fileInputRef = useRef<HTMLInputElement>(null);
const [sizeError, setSizeError] = useState(false);
return (
<div>
<button class="button" onClick={(e) => fileInputRef.current?.click()}>
<span>{props.label}</span>
</button>
<input
ref={fileInputRef}
style={{ display: 'none' }}
type="file"
onChange={(e) => {
const f: FileList | null = e.currentTarget.files;
if (!f || f.length != 1)
return props.onChange(undefined);
console.log(f);
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
setSizeError(true);
return props.onChange(undefined);
}
setSizeError(false);
return f[0].arrayBuffer().then((b) => {
const content = new Uint8Array(b).reduce(
(data, byte) => data + String.fromCharCode(byte),
'',
);
return props.onChange({
content,
name: f[0].name,
type: f[0].type,
});
});
}}
/>
{sizeError && (
<p class="help is-danger">File should be smaller than 1 MB</p>
)}
</div>
);
}

View File

@ -0,0 +1,74 @@
/*
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';
export interface Notification {
message: string;
description?: string | VNode;
type: MessageType;
}
export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS';
interface Props {
notifications: Notification[];
removeNotification?: (n: Notification) => void;
}
function messageStyle(type: MessageType): string {
switch (type) {
case 'INFO':
return 'message is-info';
case 'WARN':
return 'message is-warning';
case 'ERROR':
return 'message is-danger';
case 'SUCCESS':
return 'message is-success';
default:
return 'message';
}
}
export function Notifications({
notifications,
removeNotification,
}: Props): VNode {
return (
<div class="block">
{notifications.map((n, i) => (
<article key={i} class={messageStyle(n.type)}>
<div class="message-header">
<p>{n.message}</p>
{removeNotification && (
<button
class="delete"
onClick={() => removeNotification && removeNotification(n)}
/>
)}
</div>
{n.description && <div class="message-body">{n.description}</div>}
</article>
))}
</div>
);
}

View File

@ -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/>
*/
import { h, VNode } from 'preact';
import { useEffect, useRef } from 'preact/hooks';
import qrcode from 'qrcode-generator';
export function QR({ text }: { text: string }): VNode {
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const qr = qrcode(0, 'L');
qr.addData(text);
qr.make();
if (divRef.current)
divRef.current.innerHTML = qr.createSvgTag({
scalable: true,
});
});
return (
<div
style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'left',
}}
>
<div
style={{ width: '50%', minWidth: 200, maxWidth: 300 }}
ref={divRef}
/>
</div>
);
}

View File

@ -0,0 +1,14 @@
import { FunctionalComponent, h } from 'preact';
import { TranslationProvider } from '../context/translation';
import { BankHome } from '../pages/home/index';
import { Menu } from './menu';
const App: FunctionalComponent = () => {
return (
<TranslationProvider>
<BankHome />
</TranslationProvider>
);
};
export default App;

View File

@ -0,0 +1,90 @@
import { format, subYears } from 'date-fns';
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { DatePicker } from '../picker/DatePicker';
export interface DateInputProps {
label: string;
grabFocus?: boolean;
tooltip?: string;
error?: string;
years?: Array<number>;
onConfirm?: () => void;
bind: [string, (x: string) => void];
}
export function DateInput(props: DateInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
}, [props.grabFocus]);
const [opened, setOpened] = useState(false);
const value = props.bind[0] || '';
const [dirty, setDirty] = useState(false);
const showError = dirty && props.error;
const calendar = subYears(new Date(), 30);
return (
<div class="field">
<label class="label">
{props.label}
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
<i class="mdi mdi-information" />
</span>
)}
</label>
<div class="control">
<div class="field has-addons">
<p class="control">
<input
type="text"
class={showError ? 'input is-danger' : 'input'}
value={value}
onKeyPress={(e) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm()
}}
onInput={(e) => {
const text = e.currentTarget.value;
setDirty(true);
props.bind[1](text);
}}
ref={inputRef}
/>
</p>
<p class="control">
<a
class="button"
onClick={() => {
setOpened(true);
}}
>
<span class="icon">
<i class="mdi mdi-calendar" />
</span>
</a>
</p>
</div>
</div>
<p class="help">Using the format yyyy-mm-dd</p>
{showError && <p class="help is-danger">{props.error}</p>}
<DatePicker
opened={opened}
initialDate={calendar}
years={props.years}
closeFunction={() => setOpened(false)}
dateReceiver={(d) => {
setDirty(true);
const v = format(d, 'yyyy-MM-dd');
props.bind[1](v);
}}
/>
</div>
);
}

View File

@ -0,0 +1,57 @@
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
export interface TextInputProps {
label: string;
grabFocus?: boolean;
error?: string;
placeholder?: string;
tooltip?: string;
onConfirm?: () => void;
bind: [string, (x: string) => void];
}
export function EmailInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
}, [props.grabFocus]);
const value = props.bind[0];
const [dirty, setDirty] = useState(false);
const showError = dirty && props.error;
return (
<div class="field">
<label class="label">
{props.label}
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
<i class="mdi mdi-information" />
</span>
)}
</label>
<div class="control has-icons-right">
<input
value={value}
required
placeholder={props.placeholder}
type="email"
class={showError ? 'input is-danger' : 'input'}
onKeyPress={(e) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm()
}}
onInput={(e) => {
setDirty(true);
props.bind[1]((e.target as HTMLInputElement).value);
}}
ref={inputRef}
style={{ display: 'block' }}
/>
</div>
{showError && <p class="help is-danger">{props.error}</p>}
</div>
);
}

View File

@ -0,0 +1,104 @@
/*
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 { useLayoutEffect, useRef, useState } from 'preact/hooks';
const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
export interface FileTypeContent {
content: string;
type: string;
name: string;
}
export interface FileInputProps {
label: string;
grabFocus?: boolean;
disabled?: boolean;
error?: string;
placeholder?: string;
tooltip?: string;
onChange: (v: FileTypeContent | undefined) => void;
}
export function FileInput(props: FileInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
}, [props.grabFocus]);
const fileInputRef = useRef<HTMLInputElement>(null);
const [sizeError, setSizeError] = useState(false);
return (
<div class="field">
<label class="label">
<a class="button" onClick={(e) => fileInputRef.current?.click()}>
<div class="icon is-small ">
<i class="mdi mdi-folder" />
</div>
<span>
{props.label}
</span>
</a>
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
<i class="mdi mdi-information" />
</span>
)}
</label>
<div class="control">
<input
ref={fileInputRef}
style={{ display: 'none' }}
type="file"
// name={String(name)}
onChange={(e) => {
const f: FileList | null = e.currentTarget.files;
if (!f || f.length != 1)
return props.onChange(undefined);
console.log(f)
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
setSizeError(true);
return props.onChange(undefined);
}
setSizeError(false);
return f[0].arrayBuffer().then((b) => {
const b64 = btoa(
new Uint8Array(b).reduce(
(data, byte) => data + String.fromCharCode(byte),
'',
),
);
return props.onChange({content: `data:${f[0].type};base64,${b64}`, name: f[0].name, type: f[0].type});
});
}}
/>
{props.error && <p class="help is-danger">{props.error}</p>}
{sizeError && (
<p class="help is-danger">File should be smaller than 1 MB</p>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,93 @@
/*
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 { useLayoutEffect, useRef, useState } from 'preact/hooks';
import emptyImage from '../../assets/empty.png';
import { TextInputProps } from './TextInput';
const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
export function ImageInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
}, [props.grabFocus]);
const value = props.bind[0];
// const [dirty, setDirty] = useState(false)
const image = useRef<HTMLInputElement>(null);
const [sizeError, setSizeError] = useState(false);
function onChange(v: string): void {
// setDirty(true);
props.bind[1](v);
}
return (
<div class="field">
<label class="label">
{props.label}
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
<i class="mdi mdi-information" />
</span>
)}
</label>
<div class="control">
<img
src={!value ? emptyImage : value}
style={{ width: 200, height: 200 }}
onClick={() => image.current?.click()}
/>
<input
ref={image}
style={{ display: 'none' }}
type="file"
name={String(name)}
onChange={(e) => {
const f: FileList | null = e.currentTarget.files;
if (!f || f.length != 1)
return onChange(emptyImage);
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
setSizeError(true);
return onChange(emptyImage);
}
setSizeError(false);
return f[0].arrayBuffer().then((b) => {
const b64 = btoa(
new Uint8Array(b).reduce(
(data, byte) => data + String.fromCharCode(byte),
'',
),
);
return onChange(`data:${f[0].type};base64,${b64}` as any);
});
}}
/>
{props.error && <p class="help is-danger">{props.error}</p>}
{sizeError && (
<p class="help is-danger">Image should be smaller than 1 MB</p>
)}
</div>
</div>
);
}

View File

@ -0,0 +1,56 @@
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
export interface TextInputProps {
label: string;
grabFocus?: boolean;
error?: string;
placeholder?: string;
tooltip?: string;
onConfirm?: () => void;
bind: [string, (x: string) => void];
}
export function PhoneNumberInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
}, [props.grabFocus]);
const value = props.bind[0];
const [dirty, setDirty] = useState(false);
const showError = dirty && props.error;
return (
<div class="field">
<label class="label">
{props.label}
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
<i class="mdi mdi-information" />
</span>
)}
</label>
<div class="control has-icons-right">
<input
value={value}
type="tel"
placeholder={props.placeholder}
class={showError ? 'input is-danger' : 'input'}
onKeyPress={(e) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm()
}}
onInput={(e) => {
setDirty(true);
props.bind[1]((e.target as HTMLInputElement).value);
}}
ref={inputRef}
style={{ display: 'block' }}
/>
</div>
{showError && <p class="help is-danger">{props.error}</p>}
</div>
);
}

View File

@ -0,0 +1,68 @@
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
export interface TextInputProps {
inputType?: 'text' | 'number' | 'multiline' | 'password';
label: string;
grabFocus?: boolean;
disabled?: boolean;
error?: string;
placeholder?: string;
tooltip?: string;
onConfirm?: () => void;
bind: [string, (x: string) => void];
}
const TextInputType = function ({ inputType, grabFocus, ...rest }: any): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (grabFocus)
inputRef.current?.focus();
}, [grabFocus]);
return inputType === 'multiline' ? (
<textarea {...rest} rows={5} ref={inputRef} style={{ height: 'unset' }} />
) : (
<input {...rest} type={inputType} ref={inputRef} />
);
};
export function TextInput(props: TextInputProps): VNode {
const value = props.bind[0];
const [dirty, setDirty] = useState(false);
const showError = dirty && props.error;
return (
<div class="field">
<label class="label">
{props.label}
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
<i class="mdi mdi-information" />
</span>
)}
</label>
<div class="control has-icons-right">
<TextInputType
inputType={props.inputType}
value={value}
grabFocus={props.grabFocus}
disabled={props.disabled}
placeholder={props.placeholder}
class={showError ? 'input is-danger' : 'input'}
onKeyPress={(e: any) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm();
}}
onInput={(e: any) => {
setDirty(true);
props.bind[1]((e.target as HTMLInputElement).value);
}}
style={{ display: 'block' }}
/>
</div>
{showError && <p class="help is-danger">{props.error}</p>}
</div>
);
}

View File

@ -0,0 +1,101 @@
/*
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 { useCallback, useEffect, useState } from 'preact/hooks';
import langIcon from '../../assets/icons/languageicon.svg';
import { useTranslationContext } from '../../context/translation';
import { strings as messages } from '../../i18n/strings';
type LangsNames = {
[P in keyof typeof messages]: string;
};
const names: LangsNames = {
es: 'Español [es]',
en: 'English [en]',
fr: 'Français [fr]',
de: 'Deutsch [de]',
sv: 'Svenska [sv]',
it: 'Italiano [it]',
};
function getLangName(s: keyof LangsNames | string): string {
if (names[s]) return names[s];
return String(s);
}
// FIXME: explain "like py".
export function LangSelectorLikePy(): VNode {
const [updatingLang, setUpdatingLang] = useState(false);
const { lang, changeLanguage } = useTranslationContext();
const [hidden, setHidden] = useState(true)
useEffect(() => {
function bodyKeyPress(event:KeyboardEvent) {
if (event.code === 'Escape')
setHidden(true);
}
function bodyOnClick(event:Event) {
setHidden(true);
}
document.body.addEventListener('click', bodyOnClick)
document.body.addEventListener('keydown', bodyKeyPress as any)
return () => {
document.body.removeEventListener('keydown', bodyKeyPress as any)
document.body.removeEventListener('click', bodyOnClick)
}
},[])
return (
<Fragment>
<button name="language" onClick={(ev) => {
setHidden(h => !h);
ev.stopPropagation();
}}>
{getLangName(lang)}
</button>
<div id="lang" class={hidden ? 'hide' : ''}>
<div style="position: relative; overflow: visible;">
<div
class="nav"
style="position: absolute; max-height: 60vh; overflow-y: scroll">
{Object.keys(messages)
.filter((l) => l !== lang)
.map((l) => (
<a
key={l}
href="#"
class="navbtn langbtn"
value={l}
onClick={() => {
changeLanguage(l);
setUpdatingLang(false);
}}>
{getLangName(l)}
</a>
))}
<br />
</div>
</div>
</div>
</Fragment>
);
}

View File

@ -0,0 +1,53 @@
/*
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 logo from '../../assets/logo.jpeg';
import { LangSelectorLikePy as LangSelector } from './LangSelector';
interface Props {
onMobileMenu: () => void;
title: string;
}
export function NavigationBar({ onMobileMenu, title }: Props): VNode {
return (
<nav
class="navbar is-fixed-top"
role="navigation"
aria-label="main navigation"
>
<div class="navbar-brand">
<span class="navbar-item" style={{ fontSize: 24, fontWeight: 900 }}>
{title}
</span>
</div>
<div class="navbar-menu ">
<div class="navbar-end">
<div class="navbar-item" style={{ paddingTop: 4, paddingBottom: 4 }}>
{/* <LangSelector /> */}
</div>
</div>
</div>
</nav>
);
}

View File

@ -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/>
*/
/**
*
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import { Translate } from '../../i18n';
interface Props {
mobile?: boolean;
}
export function Sidebar({ mobile }: Props): VNode {
// const config = useConfigContext();
const config = { version: 'none' };
// FIXME: add replacement for __VERSION__ with the current version
const process = { env: { __VERSION__: '0.0.0' } };
return (
<aside class="aside is-placed-left is-expanded">
<div class="aside-tools">
<div class="aside-tools-label">
<div>
<b>euFin bank</b>
</div>
<div
class="is-size-7 has-text-right"
style={{ lineHeight: 0, marginTop: -10 }}
>
Version {process.env.__VERSION__} ({config.version})
</div>
</div>
</div>
<div class="menu is-menu-main">
<p class="menu-label">
<Translate>Bank menu</Translate>
</p>
<ul class="menu-list">
<li>
<div class="ml-4">
<span class="menu-item-label">
<Translate>Select option1</Translate>
</span>
</div>
</li>
<li>
<div class="ml-4">
<span class="menu-item-label">
<Translate>Select option2</Translate>
</span>
</div>
</li>
</ul>
</div>
</aside>
);
}

View File

@ -0,0 +1,135 @@
/*
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 { ComponentChildren, Fragment, h, VNode } from 'preact';
import Match from 'preact-router/match';
import { useEffect, useState } from 'preact/hooks';
import { NavigationBar } from './NavigationBar';
import { Sidebar } from './SideBar';
interface MenuProps {
title: string;
}
function WithTitle({
title,
children,
}: {
title: string;
children: ComponentChildren;
}): VNode {
useEffect(() => {
document.title = `${title}`;
}, [title]);
return <Fragment>{children}</Fragment>;
}
export function Menu({ title }: MenuProps): VNode {
const [mobileOpen, setMobileOpen] = useState(false);
return (
<Match>
{({ path }: { path: string }) => {
const titleWithSubtitle = title; // title ? title : (!admin ? getInstanceTitle(path, instance) : getAdminTitle(path, instance))
return (
<WithTitle title={titleWithSubtitle}>
<div
class={mobileOpen ? 'has-aside-mobile-expanded' : ''}
onClick={() => setMobileOpen(false)}
>
<NavigationBar
onMobileMenu={() => setMobileOpen(!mobileOpen)}
title={titleWithSubtitle}
/>
<Sidebar mobile={mobileOpen} />
</div>
</WithTitle>
);
}}
</Match>
);
}
interface NotYetReadyAppMenuProps {
title: string;
onLogout?: () => void;
}
interface NotifProps {
notification?: Notification;
}
export function NotificationCard({
notification: n,
}: NotifProps): VNode | null {
if (!n) return null;
return (
<div class="notification">
<div class="columns is-vcentered">
<div class="column is-12">
<article
class={
n.type === 'ERROR'
? 'message is-danger'
: n.type === 'WARN'
? 'message is-warning'
: 'message is-info'
}
>
<div class="message-header">
<p>{n.message}</p>
</div>
{n.description && <div class="message-body">{n.description}</div>}
</article>
</div>
</div>
</div>
);
}
export function NotYetReadyAppMenu({
onLogout,
title,
}: NotYetReadyAppMenuProps): VNode {
const [mobileOpen, setMobileOpen] = useState(false);
useEffect(() => {
document.title = `Taler Backoffice: ${title}`;
}, [title]);
return (
<div
class="has-aside-mobile-expanded"
// class={mobileOpen ? "has-aside-mobile-expanded" : ""}
onClick={() => setMobileOpen(false)}
>
<NavigationBar
onMobileMenu={() => setMobileOpen(!mobileOpen)}
title={title}
/>
{onLogout && <Sidebar mobile={mobileOpen} />}
</div>
);
}
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';

View File

@ -0,0 +1,356 @@
/*
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, Component } from 'preact';
interface Props {
closeFunction?: () => void;
dateReceiver?: (d: Date) => void;
initialDate?: Date;
years?: Array<number>;
opened?: boolean;
}
interface State {
displayedMonth: number;
displayedYear: number;
selectYearMode: boolean;
currentDate: Date;
}
const now = new Date();
const monthArrShortFull = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
const monthArrShort = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const dayArr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const yearArr: number[] = [];
// inspired by https://codepen.io/m4r1vs/pen/MOOxyE
export class DatePicker extends Component<Props, State> {
closeDatePicker() {
this.props.closeFunction && this.props.closeFunction(); // Function gets passed by parent
}
/**
* Gets fired when a day gets clicked.
* @param {object} e The event thrown by the <span /> element clicked
*/
dayClicked(e: any) {
const element = e.target; // the actual element clicked
if (element.innerHTML === '') return false; // don't continue if <span /> empty
// get date from clicked element (gets attached when rendered)
const date = new Date(element.getAttribute('data-value'));
// update the state
this.setState({ currentDate: date });
this.passDateToParent(date);
}
/**
* returns days in month as array
* @param {number} month the month to display
* @param {number} year the year to display
*/
getDaysByMonth(month: number, year: number) {
const calendar = [];
const date = new Date(year, month, 1); // month to display
const firstDay = new Date(year, month, 1).getDay(); // first weekday of month
const lastDate = new Date(year, month + 1, 0).getDate(); // last date of month
let day: number | null = 0;
// the calendar is 7*6 fields big, so 42 loops
for (let i = 0; i < 42; i++) {
if (i >= firstDay && day !== null) day = day + 1;
if (day !== null && day > lastDate) day = null;
// append the calendar Array
calendar.push({
day: day === 0 || day === null ? null : day, // null or number
date: day === 0 || day === null ? null : new Date(year, month, day), // null or Date()
today:
day === now.getDate() &&
month === now.getMonth() &&
year === now.getFullYear(), // boolean
});
}
return calendar;
}
/**
* Display previous month by updating state
*/
displayPrevMonth() {
if (this.state.displayedMonth <= 0)
this.setState({
displayedMonth: 11,
displayedYear: this.state.displayedYear - 1,
});
else
this.setState({
displayedMonth: this.state.displayedMonth - 1,
});
}
/**
* Display next month by updating state
*/
displayNextMonth() {
if (this.state.displayedMonth >= 11)
this.setState({
displayedMonth: 0,
displayedYear: this.state.displayedYear + 1,
});
else
this.setState({
displayedMonth: this.state.displayedMonth + 1,
});
}
/**
* Display the selected month (gets fired when clicking on the date string)
*/
displaySelectedMonth() {
if (this.state.selectYearMode)
this.toggleYearSelector();
else {
if (!this.state.currentDate) return false;
this.setState({
displayedMonth: this.state.currentDate.getMonth(),
displayedYear: this.state.currentDate.getFullYear(),
});
}
}
toggleYearSelector() {
this.setState({ selectYearMode: !this.state.selectYearMode });
}
changeDisplayedYear(e: any) {
const element = e.target;
this.toggleYearSelector();
this.setState({
displayedYear: parseInt(element.innerHTML, 10),
displayedMonth: 0,
});
}
/**
* Pass the selected date to parent when 'OK' is clicked
*/
passSavedDateDateToParent() {
this.passDateToParent(this.state.currentDate);
}
passDateToParent(date: Date) {
if (typeof this.props.dateReceiver === 'function')
this.props.dateReceiver(date);
this.closeDatePicker();
}
componentDidUpdate() {
// if (this.state.selectYearMode) {
// document.getElementsByClassName('selected')[0].scrollIntoView(); // works in every browser incl. IE, replace with scrollIntoViewIfNeeded when browsers support it
// }
}
constructor(props: any) {
super(props);
this.closeDatePicker = this.closeDatePicker.bind(this);
this.dayClicked = this.dayClicked.bind(this);
this.displayNextMonth = this.displayNextMonth.bind(this);
this.displayPrevMonth = this.displayPrevMonth.bind(this);
this.getDaysByMonth = this.getDaysByMonth.bind(this);
this.changeDisplayedYear = this.changeDisplayedYear.bind(this);
this.passDateToParent = this.passDateToParent.bind(this);
this.toggleYearSelector = this.toggleYearSelector.bind(this);
this.displaySelectedMonth = this.displaySelectedMonth.bind(this);
const initial = props.initialDate || now;
this.state = {
currentDate: initial,
displayedMonth: initial.getMonth(),
displayedYear: initial.getFullYear(),
selectYearMode: false,
};
}
render() {
const {
currentDate,
displayedMonth,
displayedYear,
selectYearMode,
} = this.state;
return (
<div>
<div class={`datePicker ${this.props.opened && 'datePicker--opened'}`}>
<div class="datePicker--titles">
<h3
style={{
color: selectYearMode
? 'rgba(255,255,255,.87)'
: 'rgba(255,255,255,.57)',
}}
onClick={this.toggleYearSelector}
>
{currentDate.getFullYear()}
</h3>
<h2
style={{
color: !selectYearMode
? 'rgba(255,255,255,.87)'
: 'rgba(255,255,255,.57)',
}}
onClick={this.displaySelectedMonth}
>
{dayArr[currentDate.getDay()]},{' '}
{monthArrShort[currentDate.getMonth()]} {currentDate.getDate()}
</h2>
</div>
{!selectYearMode && (
<nav>
<span onClick={this.displayPrevMonth} class="icon">
<i
style={{ transform: 'rotate(180deg)' }}
class="mdi mdi-forward"
/>
</span>
<h4>
{monthArrShortFull[displayedMonth]} {displayedYear}
</h4>
<span onClick={this.displayNextMonth} class="icon">
<i class="mdi mdi-forward" />
</span>
</nav>
)}
<div class="datePicker--scroll">
{!selectYearMode && (
<div class="datePicker--calendar">
<div class="datePicker--dayNames">
{['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, i) => (
<span key={i}>{day}</span>
))}
</div>
<div onClick={this.dayClicked} class="datePicker--days">
{/*
Loop through the calendar object returned by getDaysByMonth().
*/}
{this.getDaysByMonth(
this.state.displayedMonth,
this.state.displayedYear,
).map((day) => {
let selected = false;
if (currentDate && day.date)
selected =
currentDate.toLocaleDateString() ===
day.date.toLocaleDateString();
return (
<span
key={day.day}
class={
(day.today ? 'datePicker--today ' : '') +
(selected ? 'datePicker--selected' : '')
}
disabled={!day.date}
data-value={day.date}
>
{day.day}
</span>
);
})}
</div>
</div>
)}
{selectYearMode && (
<div class="datePicker--selectYear">
{(this.props.years || yearArr).map((year) => (
<span
key={year}
class={year === displayedYear ? 'selected' : ''}
onClick={this.changeDisplayedYear}
>
{year}
</span>
))}
</div>
)}
</div>
</div>
<div
class="datePicker--background"
onClick={this.closeDatePicker}
style={{
display: this.props.opened ? 'block' : 'none',
}}
/>
</div>
);
}
}
for (let i = 2010; i <= now.getFullYear() + 10; i++)
yearArr.push(i);

View File

@ -0,0 +1,55 @@
/*
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, FunctionalComponent } from 'preact';
import { useState } from 'preact/hooks';
import { DurationPicker as TestedComponent } from './DurationPicker';
export default {
title: 'Components/Picker/Duration',
component: TestedComponent,
argTypes: {
onCreate: { action: 'onCreate' },
goBack: { action: 'goBack' },
},
};
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, {
days: true,
minutes: true,
hours: true,
seconds: true,
value: 10000000,
});
export const WithState = () => {
const [v, s] = useState<number>(1000000);
return <TestedComponent value={v} onChange={s} days minutes hours seconds />;
};

View File

@ -0,0 +1,211 @@
/*
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 { useState } from 'preact/hooks';
import { useTranslator } from '../../i18n';
import '../../scss/DurationPicker.scss';
export interface Props {
hours?: boolean;
minutes?: boolean;
seconds?: boolean;
days?: boolean;
onChange: (value: number) => void;
value: number;
}
// inspiration taken from https://github.com/flurmbo/react-duration-picker
export function DurationPicker({
days,
hours,
minutes,
seconds,
onChange,
value,
}: Props): VNode {
const ss = 1000;
const ms = ss * 60;
const hs = ms * 60;
const ds = hs * 24;
const i18n = useTranslator();
return (
<div class="rdp-picker">
{days && (
<DurationColumn
unit={i18n`days`}
max={99}
value={Math.floor(value / ds)}
onDecrease={value >= ds ? () => onChange(value - ds) : undefined}
onIncrease={value < 99 * ds ? () => onChange(value + ds) : undefined}
onChange={(diff) => onChange(value + diff * ds)}
/>
)}
{hours && (
<DurationColumn
unit={i18n`hours`}
max={23}
min={1}
value={Math.floor(value / hs) % 24}
onDecrease={value >= hs ? () => onChange(value - hs) : undefined}
onIncrease={value < 99 * ds ? () => onChange(value + hs) : undefined}
onChange={(diff) => onChange(value + diff * hs)}
/>
)}
{minutes && (
<DurationColumn
unit={i18n`minutes`}
max={59}
min={1}
value={Math.floor(value / ms) % 60}
onDecrease={value >= ms ? () => onChange(value - ms) : undefined}
onIncrease={value < 99 * ds ? () => onChange(value + ms) : undefined}
onChange={(diff) => onChange(value + diff * ms)}
/>
)}
{seconds && (
<DurationColumn
unit={i18n`seconds`}
max={59}
value={Math.floor(value / ss) % 60}
onDecrease={value >= ss ? () => onChange(value - ss) : undefined}
onIncrease={value < 99 * ds ? () => onChange(value + ss) : undefined}
onChange={(diff) => onChange(value + diff * ss)}
/>
)}
</div>
);
}
interface ColProps {
unit: string;
min?: number;
max: number;
value: number;
onIncrease?: () => void;
onDecrease?: () => void;
onChange?: (diff: number) => void;
}
function InputNumber({
initial,
onChange,
}: {
initial: number;
onChange: (n: number) => void;
}) {
const [value, handler] = useState<{ v: string }>({
v: toTwoDigitString(initial),
});
return (
<input
value={value.v}
onBlur={(e) => onChange(parseInt(value.v, 10))}
onInput={(e) => {
e.preventDefault();
const n = Number.parseInt(e.currentTarget.value, 10);
if (isNaN(n)) return handler({ v: toTwoDigitString(initial) });
return handler({ v: toTwoDigitString(n) });
}}
style={{
width: 50,
border: 'none',
fontSize: 'inherit',
background: 'inherit',
}}
/>
);
}
function DurationColumn({
unit,
min = 0,
max,
value,
onIncrease,
onDecrease,
onChange,
}: ColProps): VNode {
const cellHeight = 35;
return (
<div class="rdp-column-container">
<div class="rdp-masked-div">
<hr class="rdp-reticule" style={{ top: cellHeight * 2 - 1 }} />
<hr class="rdp-reticule" style={{ top: cellHeight * 3 - 1 }} />
<div class="rdp-column" style={{ top: 0 }}>
<div class="rdp-cell" key={value - 2}>
{onDecrease && (
<button
style={{ width: '100%', textAlign: 'center', margin: 5 }}
onClick={onDecrease}
>
<span class="icon">
<i class="mdi mdi-chevron-up" />
</span>
</button>
)}
</div>
<div class="rdp-cell" key={value - 1}>
{value > min ? toTwoDigitString(value - 1) : ''}
</div>
<div class="rdp-cell rdp-center" key={value}>
{onChange ? (
<InputNumber
initial={value}
onChange={(n) => onChange(n - value)}
/>
) : (
toTwoDigitString(value)
)}
<div>{unit}</div>
</div>
<div class="rdp-cell" key={value + 1}>
{value < max ? toTwoDigitString(value + 1) : ''}
</div>
<div class="rdp-cell" key={value + 2}>
{onIncrease && (
<button
style={{ width: '100%', textAlign: 'center', margin: 5 }}
onClick={onIncrease}
>
<span class="icon">
<i class="mdi mdi-chevron-down" />
</span>
</button>
)}
</div>
</div>
</div>
</div>
);
}
function toTwoDigitString(n: number) {
if (n < 10)
return `0${n}`;
return `${n}`;
}

View File

@ -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/>
*/
/**
*
* @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: () => {
/**
* This function will be replaced by one with
* the same signature _but_ coming from the state.
* FIXME: clarify this design.
*/
},
};
const Context = createContext<Type>(initial);
interface Props {
initial?: string;
children: any;
forceLang?: string;
}
// Outmost UI wrapper.
export const TranslationProvider = ({
initial,
children,
forceLang,
}: Props): VNode => {
const [lang, changeLanguage] = useLang(initial);
useEffect(() => {
if (forceLang)
changeLanguage(forceLang);
});
console.log('lang store', strings);
const handler = new jedLib.Jed(strings[lang] || strings['en']);
return h(Context.Provider, {
value: { lang, handler, changeLanguage },
children,
});
};
export const useTranslationContext = (): Type => useContext(Context);

View File

@ -0,0 +1,20 @@
declare module '*.css' {
const mapping: Record<string, string>;
export default mapping;
}
declare module '*.svg' {
const content: any;
export default content;
}
declare module '*.jpeg' {
const content: any;
export default content;
}
declare module '*.png' {
const content: any;
export default content;
}
declare module 'jed' {
const x: any;
export = x;
}

View File

@ -0,0 +1,80 @@
/*
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 {
console.log('calling async', args);
const result = await fn(...args);
console.log('async back', result);
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,
};
}

View File

@ -0,0 +1,151 @@
/*
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, useState } from 'preact/hooks';
export type ValueOrFunction<T> = T | ((p: T) => T);
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);
const [value, setValue] = useNotNullLocalStorage('lang-preference', defaultLang);
function updateValue(newValue: (string | ((v: string) => string))) {
if (document.body.parentElement) {
const htmlElement = document.body.parentElement
if (typeof newValue === 'string') {
htmlElement.lang = newValue;
setValue(newValue)
} else if (typeof newValue === 'function')
setValue((old) => {
const nv = newValue(old)
htmlElement.lang = nv;
return nv
})
} else setValue(newValue)
}
return [value, updateValue]
}
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];
}

View File

@ -0,0 +1,258 @@
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:55
#, c-format
msgid "days"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:65
#, c-format
msgid "hours"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:76
#, c-format
msgid "minutes"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:87
#, c-format
msgid "seconds"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:734
#, c-format
msgid "Clear"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:761
#, c-format
msgid "Logout"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:782
#, c-format
msgid "Demo Bank"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:837
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:840
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1189
#, c-format
msgid "Go back"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:845
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:906
#, c-format
msgid "Wire transfer"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:846
#, c-format
msgid "Transfer money to another account of this bank:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:897
#, c-format
msgid "Want to try the raw payto://-format?"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:907
#, c-format
msgid "Transfer money via the Payto system:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:916
#, c-format
msgid "payto address"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:926
#, c-format
msgid "Confirm"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:956
#, c-format
msgid "Confirm Withdrawal"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1026
#, c-format
msgid "Waiting the bank to create the operaion..."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1044
#, c-format
msgid "This withdrawal was aborted!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1051
#, c-format
msgid "Withdraw to a Taler Wallet"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1052
#, c-format
msgid "You can use this QR code to withdraw to your mobile wallet:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1054
#, c-format
msgid "this link"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1060
#, c-format
msgid "Abort"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1084
#, c-format
msgid "Start withdrawal"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1101
#, c-format
msgid "Withdraw Money into a Taler wallet"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1105
#, c-format
msgid "Amount to withdraw"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1137
#, c-format
msgid "Please login!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1169
#, c-format
msgid "Login"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1184
#, c-format
msgid "Register to the euFin bank!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1194
#, c-format
msgid "Registration form"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1232
#, c-format
msgid "Register"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1272
#, c-format
msgid "Date"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1273
#, c-format
msgid "Amount"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1274
#, c-format
msgid "Counterpart"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1275
#, c-format
msgid "Subject"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1343
#, c-format
msgid "Username or account label '%1$s' not found. Won't login."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1365
#, c-format
msgid "Wrong credentials given."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1374
#, c-format
msgid "Account information could not be retrieved."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1394
#, c-format
msgid "Close wire transfer"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1412
#, c-format
msgid "Close Taler withdrawal"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1457
#, c-format
msgid "Bank account balance:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1469
#, c-format
msgid "Latest transactions:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1474
#, c-format
msgid "Transfer money manually"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1543
#, c-format
msgid "List of public accounts was not found."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1552
#, c-format
msgid "List of public accounts could not be retrieved."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1584
#, c-format
msgid "History of public accounts"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1643
#, c-format
msgid "Page has a problem: logged in but backend state is lost."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1667
#, c-format
msgid "Welcome to the euFin bank!"
msgstr ""
# 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"

View File

@ -0,0 +1,257 @@
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:55
#, c-format
msgid "days"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:65
#, c-format
msgid "hours"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:76
#, c-format
msgid "minutes"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:87
#, c-format
msgid "seconds"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:734
#, c-format
msgid "Clear"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:761
#, c-format
msgid "Logout"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:782
#, c-format
msgid "Demo Bank"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:837
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:840
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1189
#, c-format
msgid "Go back"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:845
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:906
#, c-format
msgid "Wire transfer"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:846
#, c-format
msgid "Transfer money to another account of this bank:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:897
#, c-format
msgid "Want to try the raw payto://-format?"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:907
#, c-format
msgid "Transfer money via the Payto system:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:916
#, c-format
msgid "payto address"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:926
#, c-format
msgid "Confirm"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:956
#, c-format
msgid "Confirm Withdrawal"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1026
#, c-format
msgid "Waiting the bank to create the operaion..."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1044
#, c-format
msgid "This withdrawal was aborted!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1051
#, c-format
msgid "Withdraw to a Taler Wallet"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1052
#, c-format
msgid "You can use this QR code to withdraw to your mobile wallet:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1054
#, c-format
msgid "this link"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1060
#, c-format
msgid "Abort"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1084
#, c-format
msgid "Start withdrawal"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1101
#, c-format
msgid "Withdraw Money into a Taler wallet"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1105
#, c-format
msgid "Amount to withdraw"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1137
#, c-format
msgid "Please login!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1169
#, c-format
msgid "Login"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1184
#, c-format
msgid "Register to the euFin bank!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1194
#, c-format
msgid "Registration form"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1232
#, c-format
msgid "Register"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1272
#, c-format
msgid "Date"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1273
#, c-format
msgid "Amount"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1274
#, c-format
msgid "Counterpart"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1275
#, c-format
msgid "Subject"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1343
#, c-format
msgid "Username or account label '%1$s' not found. Won't login."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1365
#, c-format
msgid "Wrong credentials given."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1374
#, c-format
msgid "Account information could not be retrieved."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1394
#, c-format
msgid "Close wire transfer"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1412
#, c-format
msgid "Close Taler withdrawal"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1457
#, c-format
msgid "Bank account balance:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1469
#, c-format
msgid "Latest transactions:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1474
#, c-format
msgid "Transfer money manually"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1543
#, c-format
msgid "List of public accounts was not found."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1552
#, c-format
msgid "List of public accounts could not be retrieved."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1584
#, c-format
msgid "History of public accounts"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1643
#, c-format
msgid "Page has a problem: logged in but backend state is lost."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1667
#, c-format
msgid "Welcome to the euFin bank!"
msgstr ""
# 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/>
#
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: 2022-01-08 09:57+0100\n"
"Last-Translator: <translate@taler.net>\n"
"Language-Team: German\n"
"Language: de\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"

View File

@ -0,0 +1,266 @@
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:55
#, c-format
msgid "days"
msgstr "days"
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:65
#, c-format
msgid "hours"
msgstr "hours"
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:76
#, c-format
msgid "minutes"
msgstr "minutes"
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:87
#, c-format
msgid "seconds"
msgstr "seconds"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:734
#, c-format
msgid "Clear"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:761
#, c-format
msgid "Logout"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:782
#, c-format
msgid "Demo Bank"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:837
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:840
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1189
#, c-format
msgid "Go back"
msgstr "Go back"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:845
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:906
#, c-format
msgid "Wire transfer"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:846
#, c-format
msgid "Transfer money to another account of this bank:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:897
#, c-format
msgid "Want to try the raw payto://-format?"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:907
#, c-format
msgid "Transfer money via the Payto system:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:916
#, c-format
msgid "payto address"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:926
#, c-format
msgid "Confirm"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:956
#, fuzzy, c-format
msgid "Confirm Withdrawal"
msgstr "Confirm withdrawal"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1026
#, c-format
msgid "Waiting the bank to create the operaion..."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1044
#, c-format
msgid "This withdrawal was aborted!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1051
#, fuzzy, c-format
msgid "Withdraw to a Taler Wallet"
msgstr "Charge Taler wallet"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1052
#, c-format
msgid "You can use this QR code to withdraw to your mobile wallet:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1054
#, c-format
msgid "this link"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1060
#, c-format
msgid "Abort"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1084
#, fuzzy, c-format
msgid "Start withdrawal"
msgstr "Start withdrawal"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1101
#, fuzzy, c-format
msgid "Withdraw Money into a Taler wallet"
msgstr "Charge Taler wallet"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1105
#, fuzzy, c-format
msgid "Amount to withdraw"
msgstr "Amount to withdraw"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1137
#, c-format
msgid "Please login!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1169
#, c-format
msgid "Login"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1184
#, c-format
msgid "Register to the euFin bank!"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1194
#, c-format
msgid "Registration form"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1232
#, c-format
msgid "Register"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1272
#, c-format
msgid "Date"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1273
#, c-format
msgid "Amount"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1274
#, c-format
msgid "Counterpart"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1275
#, c-format
msgid "Subject"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1343
#, c-format
msgid "Username or account label '%1$s' not found. Won't login."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1365
#, c-format
msgid "Wrong credentials given."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1374
#, c-format
msgid "Account information could not be retrieved."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1394
#, c-format
msgid "Close wire transfer"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1412
#, fuzzy, c-format
msgid "Close Taler withdrawal"
msgstr "Close Taler withdrawal"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1457
#, c-format
msgid "Bank account balance:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1469
#, c-format
msgid "Latest transactions:"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1474
#, c-format
msgid "Transfer money manually"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1543
#, c-format
msgid "List of public accounts was not found."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1552
#, c-format
msgid "List of public accounts could not be retrieved."
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1584
#, c-format
msgid "History of public accounts"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1643
#, c-format
msgid "Page has a problem: logged in but backend state is lost."
msgstr "Page has a problem: logged in but backend state is lost."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1667
#, fuzzy, c-format
msgid "Welcome to the euFin bank!"
msgstr "Welcome to euFin bank: Taler+IBAN now possible!"
# 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/>
#
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: 2022-01-08 09:57+0100\n"
"Last-Translator: <translate@taler.net>\n"
"Language-Team: English\n"
"Language: en\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"
#~ msgid "Page has a problem:"
#~ msgstr "Page has a problem:"
#~ msgid "Close"
#~ msgstr "Close"
#~ msgid "Sign in"
#~ msgstr "Sign in"

View File

@ -0,0 +1,211 @@
/*
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>;
}

View File

@ -0,0 +1,258 @@
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:55
#, c-format
msgid "days"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:65
#, c-format
msgid "hours"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:76
#, c-format
msgid "minutes"
msgstr ""
#: /home/job/backoffice/packages/bank/src/components/picker/DurationPicker.tsx:87
#, c-format
msgid "seconds"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:734
#, c-format
msgid "Clear"
msgstr "Cancella"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:761
#, c-format
msgid "Logout"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:782
#, c-format
msgid "Demo Bank"
msgstr "Banca 'demo'"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:837
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:840
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1189
#, c-format
msgid "Go back"
msgstr "Indietro"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:845
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:906
#, c-format
msgid "Wire transfer"
msgstr "Bonifico"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:846
#, c-format
msgid "Transfer money to another account of this bank:"
msgstr "Trasferisci fondi a un altro conto di questa banca:"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:897
#, c-format
msgid "Want to try the raw payto://-format?"
msgstr "Prova il trasferimento tramite il formato Payto!"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:907
#, c-format
msgid "Transfer money via the Payto system:"
msgstr "Effettua un bonifico tramite il sistema Payto:"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:916
#, c-format
msgid "payto address"
msgstr "indirizzo Payto"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:926
#, c-format
msgid "Confirm"
msgstr "Conferma"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:956
#, c-format
msgid "Confirm Withdrawal"
msgstr "Conferma il ritiro"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1026
#, c-format
msgid "Waiting the bank to create the operaion..."
msgstr "La banca sta creando l'operazione..."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1044
#, c-format
msgid "This withdrawal was aborted!"
msgstr "Questo ritiro è stato annullato!"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1051
#, c-format
msgid "Withdraw to a Taler Wallet"
msgstr "Ritira contante nel portafoglio Taler"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1052
#, c-format
msgid "You can use this QR code to withdraw to your mobile wallet:"
msgstr "Usa questo codice QR per ritirare contante nel tuo wallet:"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1054
#, c-format
msgid "this link"
msgstr "questo link"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1060
#, c-format
msgid "Abort"
msgstr "Annulla"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1084
#, c-format
msgid "Start withdrawal"
msgstr "Ritira contante"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1101
#, c-format
msgid "Withdraw Money into a Taler wallet"
msgstr "Ritira contante nel portafoglio Taler"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1105
#, c-format
msgid "Amount to withdraw"
msgstr "Somma da ritirare"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1137
#, c-format
msgid "Please login!"
msgstr "Accedi!"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1169
#, c-format
msgid "Login"
msgstr "Accedi"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1184
#, c-format
msgid "Register to the euFin bank!"
msgstr "Apri un conto in banca euFin!"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1194
#, c-format
msgid "Registration form"
msgstr "Registrazione"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1232
#, c-format
msgid "Register"
msgstr "Registrati"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1272
#, c-format
msgid "Date"
msgstr ""
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1273
#, c-format
msgid "Amount"
msgstr "Somma"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1274
#, c-format
msgid "Counterpart"
msgstr "Controparte"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1275
#, c-format
msgid "Subject"
msgstr "Causale"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1343
#, c-format
msgid "Username or account label '%1$s' not found. Won't login."
msgstr "L'utente '%1$s' non esiste. Login impossibile"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1365
#, c-format
msgid "Wrong credentials given."
msgstr "Credenziali invalide."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1374
#, c-format
msgid "Account information could not be retrieved."
msgstr "Impossibile ricevere le informazioni relative al conto."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1394
#, c-format
msgid "Close wire transfer"
msgstr "Chiudi il bonifico"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1412
#, c-format
msgid "Close Taler withdrawal"
msgstr "Chiudi il ritiro Taler"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1457
#, c-format
msgid "Bank account balance:"
msgstr "Bilancio:"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1469
#, c-format
msgid "Latest transactions:"
msgstr "Ultime transazioni:"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1474
#, c-format
msgid "Transfer money manually"
msgstr "Effettua un bonifico"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1543
#, c-format
msgid "List of public accounts was not found."
msgstr "Lista conti pubblici non trovata."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1552
#, c-format
msgid "List of public accounts could not be retrieved."
msgstr "Lista conti pubblici non pervenuta."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1584
#, c-format
msgid "History of public accounts"
msgstr "Storico dei conti pubblici"
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1643
#, c-format
msgid "Page has a problem: logged in but backend state is lost."
msgstr ""
"Stato inconsistente: accesso utente effettuato ma stato con server perso."
#: /home/job/backoffice/packages/bank/src/pages/home/index.tsx:1667
#, fuzzy, c-format
msgid "Welcome to the euFin bank!"
msgstr "Benvenuti in banca euFin!"
# 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/>
#
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: 2022-01-08 10:05+0100\n"
"Last-Translator: <translate@taler.net>\n"
"Language-Team: Italian\n"
"Language: it\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"

View File

@ -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"

View File

@ -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} = {};

View File

@ -0,0 +1,472 @@
/*
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': {
'days': [
''
],
'hours': [
''
],
'minutes': [
''
],
'seconds': [
''
],
'Clear': [
''
],
'Logout': [
''
],
'Demo Bank': [
''
],
'Go back': [
''
],
'Wire transfer': [
''
],
'Transfer money to another account of this bank:': [
''
],
'Want to try the raw payto://-format?': [
''
],
'Transfer money via the Payto system:': [
''
],
'payto address': [
''
],
'Confirm': [
''
],
'Confirm Withdrawal': [
''
],
'Waiting the bank to create the operaion...': [
''
],
'This withdrawal was aborted!': [
''
],
'Withdraw to a Taler Wallet': [
''
],
'You can use this QR code to withdraw to your mobile wallet:': [
''
],
'this link': [
''
],
'Abort': [
''
],
'Start withdrawal': [
''
],
'Withdraw Money into a Taler wallet': [
''
],
'Amount to withdraw': [
''
],
'Please login!': [
''
],
'Login': [
''
],
'Register to the euFin bank!': [
''
],
'Registration form': [
''
],
'Register': [
''
],
'Date': [
''
],
'Amount': [
''
],
'Counterpart': [
''
],
'Subject': [
''
],
'Username or account label \'%1$s\' not found. Won\'t login.': [
''
],
'Wrong credentials given.': [
''
],
'Account information could not be retrieved.': [
''
],
'Close wire transfer': [
''
],
'Close Taler withdrawal': [
''
],
'Bank account balance:': [
''
],
'Latest transactions:': [
''
],
'Transfer money manually': [
''
],
'List of public accounts was not found.': [
''
],
'List of public accounts could not be retrieved.': [
''
],
'History of public accounts': [
''
],
'Page has a problem: logged in but backend state is lost.': [
''
],
'Welcome to the euFin bank!': [
''
],
'': {
'domain': 'messages',
'plural_forms': 'nplurals=2; plural=(n != 1);',
'lang': 'de'
}
}
}
};
strings['en'] = {
'domain': 'messages',
'locale_data': {
'messages': {
'days': [
'days'
],
'hours': [
'hours'
],
'minutes': [
'minutes'
],
'seconds': [
'seconds'
],
'Clear': [
''
],
'Logout': [
''
],
'Demo Bank': [
''
],
'Go back': [
'Go back'
],
'Wire transfer': [
''
],
'Transfer money to another account of this bank:': [
''
],
'Want to try the raw payto://-format?': [
''
],
'Transfer money via the Payto system:': [
''
],
'payto address': [
''
],
'Confirm': [
''
],
'Confirm Withdrawal': [
'Confirm withdrawal'
],
'Waiting the bank to create the operaion...': [
''
],
'This withdrawal was aborted!': [
''
],
'Withdraw to a Taler Wallet': [
'Charge Taler wallet'
],
'You can use this QR code to withdraw to your mobile wallet:': [
''
],
'this link': [
''
],
'Abort': [
''
],
'Start withdrawal': [
'Start withdrawal'
],
'Withdraw Money into a Taler wallet': [
'Charge Taler wallet'
],
'Amount to withdraw': [
'Amount to withdraw'
],
'Please login!': [
''
],
'Login': [
''
],
'Register to the euFin bank!': [
''
],
'Registration form': [
''
],
'Register': [
''
],
'Date': [
''
],
'Amount': [
''
],
'Counterpart': [
''
],
'Subject': [
''
],
'Username or account label \'%1$s\' not found. Won\'t login.': [
''
],
'Wrong credentials given.': [
''
],
'Account information could not be retrieved.': [
''
],
'Close wire transfer': [
''
],
'Close Taler withdrawal': [
'Close Taler withdrawal'
],
'Bank account balance:': [
''
],
'Latest transactions:': [
''
],
'Transfer money manually': [
''
],
'List of public accounts was not found.': [
''
],
'List of public accounts could not be retrieved.': [
''
],
'History of public accounts': [
''
],
'Page has a problem: logged in but backend state is lost.': [
'Page has a problem: logged in but backend state is lost.'
],
'Welcome to the euFin bank!': [
'Welcome to euFin bank: Taler+IBAN now possible!'
],
'': {
'domain': 'messages',
'plural_forms': 'nplurals=2; plural=(n != 1);',
'lang': 'en'
}
}
}
};
strings['it'] = {
'domain': 'messages',
'locale_data': {
'messages': {
'days': [
''
],
'hours': [
''
],
'minutes': [
''
],
'seconds': [
''
],
'Clear': [
'Cancella'
],
'Logout': [
''
],
'Demo Bank': [
'Banca \'demo\''
],
'Go back': [
'Indietro'
],
'Wire transfer': [
'Bonifico'
],
'Transfer money to another account of this bank:': [
'Trasferisci fondi a un altro conto di questa banca:'
],
'Want to try the raw payto://-format?': [
'Prova il trasferimento tramite il formato Payto!'
],
'Transfer money via the Payto system:': [
'Effettua un bonifico tramite il sistema Payto:'
],
'payto address': [
'indirizzo Payto'
],
'Confirm': [
'Conferma'
],
'Confirm Withdrawal': [
'Conferma il ritiro'
],
'Waiting the bank to create the operaion...': [
'La banca sta creando l\'operazione...'
],
'This withdrawal was aborted!': [
'Questo ritiro è stato annullato!'
],
'Withdraw to a Taler Wallet': [
'Ritira contante nel portafoglio Taler'
],
'You can use this QR code to withdraw to your mobile wallet:': [
'Usa questo codice QR per ritirare contante nel tuo wallet:'
],
'this link': [
'questo link'
],
'Abort': [
'Annulla'
],
'Start withdrawal': [
'Ritira contante'
],
'Withdraw Money into a Taler wallet': [
'Ritira contante nel portafoglio Taler'
],
'Amount to withdraw': [
'Somma da ritirare'
],
'Please login!': [
'Accedi!'
],
'Login': [
'Accedi'
],
'Register to the euFin bank!': [
'Apri un conto in banca euFin!'
],
'Registration form': [
'Registrazione'
],
'Register': [
'Registrati'
],
'Date': [
''
],
'Amount': [
'Somma'
],
'Counterpart': [
'Controparte'
],
'Subject': [
'Causale'
],
'Username or account label \'%1$s\' not found. Won\'t login.': [
'L\'utente \'%1$s\' non esiste. Login impossibile'
],
'Wrong credentials given.': [
'Credenziali invalide.'
],
'Account information could not be retrieved.': [
'Impossibile ricevere le informazioni relative al conto.'
],
'Close wire transfer': [
'Chiudi il bonifico'
],
'Close Taler withdrawal': [
'Chiudi il ritiro Taler'
],
'Bank account balance:': [
'Bilancio:'
],
'Latest transactions:': [
'Ultime transazioni:'
],
'Transfer money manually': [
'Effettua un bonifico'
],
'List of public accounts was not found.': [
'Lista conti pubblici non trovata.'
],
'List of public accounts could not be retrieved.': [
'Lista conti pubblici non pervenuta.'
],
'History of public accounts': [
'Storico dei conti pubblici'
],
'Page has a problem: logged in but backend state is lost.': [
'Stato inconsistente: accesso utente effettuato ma stato con server perso.'
],
'Welcome to the euFin bank!': [
'Benvenuti in banca euFin!'
],
'': {
'domain': 'messages',
'plural_forms': 'nplurals=2; plural=(n != 1);',
'lang': 'it'
}
}
}
};

View File

@ -0,0 +1,3 @@
import App from './components/app';
export default App;

View File

@ -0,0 +1,21 @@
{
"name": "taler-bank",
"short_name": "taler-bank",
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#fff",
"theme_color": "#673ab8",
"icons": [
{
"src": "/assets/icons/android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/assets/icons/android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
import { FunctionalComponent, h } from 'preact';
import { Link } from 'preact-router/match';
const Notfound: FunctionalComponent = () => {
return (
<div>
<h1>Error 404</h1>
<p>That page doesn&apos;t exist.</p>
<Link href="/">
<h4>Back to Home</h4>
</Link>
</div>
);
};
export default Notfound;

View File

@ -0,0 +1,38 @@
/*
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 } from 'preact';
import Profile from './index';
export default {
title: 'Profile/View',
component: Profile,
argTypes: {
onSelect: { action: 'onSelect' },
},
};
export const Empty = (a: any) => <Profile {...a} />;
Empty.args = {
instances: []
}

View File

@ -0,0 +1,42 @@
import { FunctionalComponent, h } from 'preact';
import { useEffect, useState } from 'preact/hooks';
interface Props {
user: string;
}
const Profile: FunctionalComponent<Props> = (props: Props) => {
const { user } = props;
const [time, setTime] = useState<number>(Date.now());
const [count, setCount] = useState<number>(0);
// gets called when this route is navigated to
useEffect(() => {
const timer = window.setInterval(() => setTime(Date.now()), 1000);
// gets called just before navigating away from the route
return (): void => {
clearInterval(timer);
};
}, []);
// update the current time
const increment = (): void => {
setCount(count + 1);
};
return (
<div>
<h1>Profile: {user}</h1>
<p>This is the user profile for a user named {user}.</p>
<div>Current time: {new Date(time).toLocaleString()}</div>
<p>
<button onClick={increment}>Click Me</button> Clicked {count} times.
</p>
</div>
);
};
export default Profile;

View File

@ -0,0 +1,70 @@
.rdp-picker {
display: flex;
height: 175px;
}
@media (max-width: 400px) {
.rdp-picker {
width: 250px;
}
}
.rdp-masked-div {
overflow: hidden;
height: 175px;
position: relative;
}
.rdp-column-container {
flex-grow: 1;
display: inline-block;
}
.rdp-column {
position: absolute;
z-index: 0;
width: 100%;
}
.rdp-reticule {
border: 0;
border-top: 2px solid rgba(109, 202, 236, 1);
height: 2px;
position: absolute;
width: 80%;
margin: 0;
z-index: 100;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.rdp-text-overlay {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
height: 35px;
font-size: 20px;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.rdp-cell div {
font-size: 17px;
color: gray;
font-style: italic;
}
.rdp-cell {
display: flex;
align-items: center;
justify-content: center;
height: 35px;
font-size: 18px;
}
.rdp-center {
font-size: 25px;
}

View File

@ -0,0 +1,128 @@
/*
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)
*/
html {
&.has-aside-left {
&.has-aside-expanded {
nav.navbar,
body {
padding-left: $aside-width;
}
}
aside.is-placed-left {
display: block;
}
}
}
aside.aside.is-expanded {
width: $aside-width;
.menu-list {
@include icon-with-update-mark($aside-icon-width);
span.menu-item-label {
display: inline-block;
}
li.is-active {
ul {
display: block;
}
background-color: $body-background-color;
}
}
}
aside.aside {
display: none;
position: fixed;
top: 0;
left: 0;
z-index: 40;
height: 100vh;
padding: 0;
box-shadow: $aside-box-shadow;
background: $aside-background-color;
.aside-tools {
display: flex;
flex-direction: row;
width: 100%;
background-color: $aside-tools-background-color;
color: $aside-tools-color;
line-height: $navbar-height;
height: $navbar-height;
padding-left: $default-padding * 0.5;
flex: 1;
.icon {
margin-right: $default-padding * 0.5;
}
}
.menu-list {
li {
a {
&.has-dropdown-icon {
position: relative;
padding-right: $aside-icon-width;
.dropdown-icon {
position: absolute;
top: $size-base * 0.5;
right: 0;
}
}
}
ul {
display: none;
border-left: 0;
background-color: darken($base-color, 2.5%);
padding-left: 0;
margin: 0 0 $default-padding * 0.5;
li {
a {
padding: $default-padding * 0.5 0 $default-padding * 0.5
$default-padding * 0.5;
font-size: $aside-submenu-font-size;
&.has-icon {
padding-left: 0;
}
&.is-active {
&:not(:hover) {
background: transparent;
}
}
}
}
}
}
}
.menu-label {
padding: 0 $default-padding * 0.5;
margin-top: $default-padding * 0.5;
margin-bottom: $default-padding * 0.5;
}
}

View File

@ -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/>
*/
/**
*
* @author Sebastian Javier Marchano (sebasjm)
*/
.card:not(:last-child) {
margin-bottom: $default-padding;
}
.card {
border-radius: $radius-large;
border: $card-border;
&.has-table {
.card-content {
padding: 0;
}
.b-table {
border-radius: $radius-large;
overflow: hidden;
}
}
&.is-card-widget {
.card-content {
padding: $default-padding * 0.5;
}
}
.card-header {
border-bottom: 1px solid $base-color-light;
}
.card-content {
hr {
margin-left: $card-content-padding * -1;
margin-right: $card-content-padding * -1;
}
}
.is-widget-icon {
.icon {
width: 5rem;
height: 5rem;
}
}
.is-widget-label {
.subtitle {
color: $grey;
}
}
}

View File

@ -0,0 +1,263 @@
/*
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/>
*/
:root {
--primary-color: #3298dc;
--primary-text-color-dark: rgba(0, 0, 0, 0.87);
--secondary-text-color-dark: rgba(0, 0, 0, 0.57);
--disabled-text-color-dark: rgba(0, 0, 0, 0.13);
--primary-text-color-light: rgba(255, 255, 255, 0.87);
--secondary-text-color-light: rgba(255, 255, 255, 0.57);
--disabled-text-color-light: rgba(255, 255, 255, 0.13);
--font-stack: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif;
--primary-card-color: #fff;
--primary-background-color: #f2f2f2;
--box-shadow-lvl-1: 0 1px 3px rgba(0, 0, 0, 0.12),
0 1px 2px rgba(0, 0, 0, 0.24);
--box-shadow-lvl-2: 0 3px 6px rgba(0, 0, 0, 0.16),
0 3px 6px rgba(0, 0, 0, 0.23);
--box-shadow-lvl-3: 0 10px 20px rgba(0, 0, 0, 0.19),
0 6px 6px rgba(0, 0, 0, 0.23);
--box-shadow-lvl-4: 0 14px 28px rgba(0, 0, 0, 0.25),
0 10px 10px rgba(0, 0, 0, 0.22);
}
.home .datePicker div {
margin-top: 0px;
margin-bottom: 0px;
}
.datePicker {
text-align: left;
background: var(--primary-card-color);
border-radius: 3px;
z-index: 200;
position: fixed;
height: auto;
max-height: 90vh;
width: 90vw;
max-width: 448px;
transform-origin: top left;
transition: transform 0.22s ease-in-out, opacity 0.22s ease-in-out;
top: 50%;
left: 50%;
opacity: 0;
transform: scale(0) translate(-50%, -50%);
user-select: none;
&.datePicker--opened {
opacity: 1;
transform: scale(1) translate(-50%, -50%);
}
.datePicker--titles {
border-top-left-radius: 3px;
border-top-right-radius: 3px;
padding: 24px;
height: 100px;
background: var(--primary-color);
h2,
h3 {
cursor: pointer;
color: #fff;
line-height: 1;
padding: 0;
margin: 0;
font-size: 32px;
}
h3 {
color: rgba(255, 255, 255, 0.57);
font-size: 18px;
padding-bottom: 2px;
}
}
nav {
padding: 20px;
height: 56px;
h4 {
width: calc(100% - 60px);
text-align: center;
display: inline-block;
padding: 0;
font-size: 14px;
line-height: 24px;
margin: 0;
position: relative;
top: -9px;
color: var(--primary-text-color);
}
i {
cursor: pointer;
color: var(--secondary-text-color);
font-size: 26px;
user-select: none;
border-radius: 50%;
&:hover {
background: var(--disabled-text-color-dark);
}
}
}
.datePicker--scroll {
overflow-y: auto;
max-height: calc(90vh - 56px - 100px);
}
.datePicker--calendar {
padding: 0 20px;
.datePicker--dayNames {
width: 100%;
display: grid;
text-align: center;
// there's probably a better way to do this, but wanted to try out CSS grid
grid-template-columns: calc(100% / 7) calc(100% / 7) calc(100% / 7) calc(
100% / 7
) calc(100% / 7) calc(100% / 7) calc(100% / 7);
span {
color: var(--secondary-text-color-dark);
font-size: 14px;
line-height: 42px;
display: inline-grid;
}
}
.datePicker--days {
width: 100%;
display: grid;
text-align: center;
grid-template-columns: calc(100% / 7) calc(100% / 7) calc(100% / 7) calc(
100% / 7
) calc(100% / 7) calc(100% / 7) calc(100% / 7);
span {
color: var(--primary-text-color-dark);
line-height: 42px;
font-size: 14px;
display: inline-grid;
transition: color 0.22s;
height: 42px;
position: relative;
cursor: pointer;
user-select: none;
border-radius: 50%;
&::before {
content: "";
position: absolute;
z-index: -1;
height: 42px;
width: 42px;
left: calc(50% - 21px);
background: var(--primary-color);
border-radius: 50%;
transition: transform 0.22s, opacity 0.22s;
transform: scale(0);
opacity: 0;
}
&[disabled="true"] {
cursor: unset;
}
&.datePicker--today {
font-weight: 700;
}
&.datePicker--selected {
color: rgba(255, 255, 255, 0.87);
&:before {
transform: scale(1);
opacity: 1;
}
}
}
}
}
.datePicker--selectYear {
padding: 0 20px;
display: block;
width: 100%;
text-align: center;
max-height: 362px;
span {
display: block;
width: 100%;
font-size: 24px;
margin: 20px auto;
cursor: pointer;
&.selected {
font-size: 42px;
color: var(--primary-color);
}
}
}
div.datePicker--actions {
width: 100%;
padding: 8px;
text-align: right;
button {
margin-bottom: 0;
font-size: 15px;
cursor: pointer;
color: var(--primary-text-color);
border: none;
margin-left: 8px;
min-width: 64px;
line-height: 36px;
background-color: transparent;
appearance: none;
padding: 0 16px;
border-radius: 3px;
transition: background-color 0.13s;
&:hover,
&:focus {
outline: none;
background-color: var(--disabled-text-color-dark);
}
}
}
}
.datePicker--background {
z-index: 199;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, 0.52);
animation: fadeIn 0.22s forwards;
}

View File

@ -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)
*/
footer.footer {
.logo {
img {
width: auto;
height: $footer-logo-height;
}
}
}
@include mobile {
.footer-copyright {
text-align: center;
}
}

View File

@ -0,0 +1,71 @@
/*
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)
*/
.field {
&.has-check {
.field-body {
margin-top: $default-padding * 0.125;
}
}
.control {
.mdi-24px.mdi-set,
.mdi-24px.mdi:before {
font-size: inherit;
}
}
}
.upload {
.upload-draggable {
display: block;
}
}
.input,
.textarea,
select {
box-shadow: none;
&:focus,
&:active {
box-shadow: none !important;
}
}
.switch input[type="checkbox"] + .check:before {
box-shadow: none;
}
.switch,
.b-checkbox.checkbox {
input[type="checkbox"] {
&:focus + .check,
&:focus:checked + .check {
box-shadow: none !important;
}
}
}
.b-checkbox.checkbox input[type="checkbox"],
.b-radio.radio input[type="radio"] {
& + .check {
border: $checkbox-border;
}
}

View File

@ -0,0 +1,55 @@
/*
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)
*/
section.hero.is-hero-bar {
background-color: $hero-bar-background;
border-bottom: $light-border;
.hero-body {
padding: $default-padding;
.level-item {
&.is-hero-avatar-item {
margin-right: $default-padding;
}
> div > .level {
margin-bottom: $default-padding * 0.5;
}
.subtitle + p {
margin-top: $default-padding * 0.5;
}
}
.button {
&.is-hero-button {
background-color: rgba($white, 0.5);
font-weight: 300;
@include transition(background-color);
&:hover {
background-color: $white;
}
}
}
}
}

View File

@ -0,0 +1,51 @@
/*
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/>
*/
.lds-ring {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 64px;
height: 64px;
margin: 8px;
border: 8px solid black;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: black transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -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)
*/
section.section.is-main-section {
padding-top: $default-padding;
}

View File

@ -0,0 +1,50 @@
/*
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)
*/
.is-user-avatar {
&.has-max-width {
max-width: $size-base * 7;
}
&.is-aligned-center {
margin: 0 auto;
}
img {
margin: 0 auto;
border-radius: $radius-rounded;
}
}
.icon.has-update-mark {
position: relative;
&:after {
content: "";
width: $icon-update-mark-size;
height: $icon-update-mark-size;
position: absolute;
top: 1px;
right: 1px;
background-color: $icon-update-mark-color;
border-radius: $radius-rounded;
}
}

View File

@ -0,0 +1,34 @@
/*
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)
*/
@mixin transition($t) {
transition: $t 250ms ease-in-out 50ms;
}
@mixin icon-with-update-mark($icon-base-width) {
.icon {
width: $icon-base-width;
&.has-update-mark:after {
right: ($icon-base-width / 2) - 0.85;
}
}
}

View File

@ -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)
*/
.modal-card {
width: $modal-card-width;
}
.modal-card-foot {
background-color: $modal-card-foot-background-color;
}
@include mobile {
.modal .animation-content .modal-card {
width: $modal-card-width-mobile;
margin: 0 auto;
}
}

View File

@ -0,0 +1,144 @@
/*
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)
*/
nav.navbar {
box-shadow: $navbar-box-shadow;
.navbar-item {
&.has-user-avatar {
.is-user-avatar {
margin-right: $default-padding * 0.5;
display: inline-flex;
width: $navbar-avatar-size;
height: $navbar-avatar-size;
}
}
&.has-divider {
border-right: $navbar-divider-border;
}
&.no-left-space {
padding-left: 0;
}
&.has-dropdown {
padding-right: 0;
padding-left: 0;
.navbar-link {
padding-right: $navbar-item-h-padding;
padding-left: $navbar-item-h-padding;
}
}
&.has-control {
padding-top: 0;
padding-bottom: 0;
}
.control {
.input {
color: $navbar-input-color;
border: 0;
box-shadow: none;
background: transparent;
&::placeholder {
color: $navbar-input-placeholder-color;
}
}
}
}
}
@include touch {
nav.navbar {
display: flex;
padding-right: 0;
.navbar-brand {
flex: 1;
&.is-right {
flex: none;
}
}
.navbar-item {
&.no-left-space-touch {
padding-left: 0;
}
}
.navbar-menu {
position: absolute;
width: 100vw;
padding-top: 0;
top: $navbar-height;
left: 0;
.navbar-item {
.icon:first-child {
margin-right: $default-padding * 0.5;
}
&.has-dropdown {
> .navbar-link {
background-color: $white-ter;
.icon:last-child {
display: none;
}
}
}
&.has-user-avatar {
> .navbar-link {
display: flex;
align-items: center;
padding-top: $default-padding * 0.5;
padding-bottom: $default-padding * 0.5;
}
}
}
}
}
}
@include desktop {
nav.navbar {
.navbar-item {
padding-right: $navbar-item-h-padding;
padding-left: $navbar-item-h-padding;
&:not(.is-desktop-icon-only) {
.icon:first-child {
margin-right: $default-padding * 0.5;
}
}
&.is-desktop-icon-only {
span:not(.icon) {
display: none;
}
}
}
}
}

View File

@ -0,0 +1,179 @@
/*
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)
*/
table.table {
thead {
th {
border-bottom-width: 1px;
}
}
td,
th {
&.checkbox-cell {
.b-checkbox.checkbox:not(.button) {
margin-right: 0;
width: 20px;
.control-label {
display: none;
padding: 0;
}
}
}
}
td {
.image {
margin: 0 auto;
width: $table-avatar-size;
height: $table-avatar-size;
}
&.is-progress-col {
min-width: 5rem;
vertical-align: middle;
}
}
}
.b-table {
.table {
border: 0;
border-radius: 0;
}
/* This stylizes buefy's pagination */
.table-wrapper {
margin-bottom: 0;
}
.table-wrapper + .level {
padding: $notification-padding;
padding-left: $card-content-padding;
padding-right: $card-content-padding;
margin: 0;
border-top: $base-color-light;
background: $notification-background-color;
.pagination-link {
background: $button-background-color;
color: $button-color;
border-color: $button-border-color;
&.is-current {
border-color: $button-active-border-color;
}
}
.pagination-previous,
.pagination-next,
.pagination-link {
border-color: $button-border-color;
color: $base-color;
&[disabled] {
background-color: transparent;
}
}
}
}
@include mobile {
.card {
&.has-table {
.b-table {
.table-wrapper + .level {
.level-left + .level-right {
margin-top: 0;
}
}
}
}
&.has-mobile-sort-spaced {
.b-table {
.field.table-mobile-sort {
padding-top: $default-padding * 0.5;
}
}
}
}
.b-table {
.field.table-mobile-sort {
padding: 0 $default-padding * 0.5;
}
.table-wrapper.has-mobile-cards {
tr {
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1);
margin-bottom: 3px !important;
}
td {
&.is-progress-col {
span,
progress {
display: flex;
width: 45%;
align-items: center;
align-self: center;
}
}
&.checkbox-cell,
&.is-image-cell {
border-bottom: 0 !important;
}
&.checkbox-cell,
&.is-actions-cell {
&:before {
display: none;
}
}
&.has-no-head-mobile {
&:before {
display: none;
}
span {
display: block;
width: 100%;
}
&.is-progress-col {
progress {
width: 100%;
}
}
&.is-image-cell {
.image {
width: $table-avatar-size-mobile;
height: auto;
margin: 0 auto $default-padding * 0.25;
}
}
}
}
}
}
}

View File

@ -0,0 +1,136 @@
/*
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)
*/
/* We'll need some initial vars to use here */
@import "node_modules/bulma/sass/utilities/initial-variables";
/* Base: Size */
$size-base: 1rem;
$default-padding: $size-base * 1.5;
/* Default font */
$family-sans-serif: "Nunito", sans-serif;
/* Base color */
$base-color: #2e323a;
$base-color-light: rgba(24, 28, 33, 0.06);
/* General overrides */
$primary: $turquoise;
$body-background-color: #f8f8f8;
$link: $blue;
$link-visited: $purple;
$light-border: 1px solid $base-color-light;
$hr-height: 1px;
/* NavBar: specifics */
$navbar-input-color: $grey-darker;
$navbar-input-placeholder-color: $grey-lighter;
$navbar-box-shadow: 0 1px 0 rgba(24, 28, 33, 0.04);
$navbar-divider-border: 1px solid rgba($grey-lighter, 0.25);
$navbar-item-h-padding: $default-padding * 0.75;
$navbar-avatar-size: 1.75rem;
/* Aside: Bulma override */
$menu-item-radius: 0;
$menu-list-link-padding: $size-base * 0.5 0;
$menu-label-color: lighten($base-color, 25%);
$menu-item-color: lighten($base-color, 30%);
$menu-item-hover-color: $white;
$menu-item-hover-background-color: darken($base-color, 3.5%);
$menu-item-active-color: $white;
$menu-item-active-background-color: darken($base-color, 2.5%);
/* Aside: specifics */
$aside-width: $size-base * 14;
$aside-mobile-width: $size-base * 15;
$aside-icon-width: $size-base * 3;
$aside-submenu-font-size: $size-base * 0.95;
$aside-box-shadow: none;
$aside-background-color: $base-color;
$aside-tools-background-color: darken($aside-background-color, 10%);
$aside-tools-color: $white;
/* Title Bar: specifics */
$title-bar-color: $grey;
$title-bar-active-color: $black-ter;
/* Hero Bar: specifics */
$hero-bar-background: $white;
/* Card: Bulma override */
$card-shadow: none;
$card-header-shadow: none;
/* Card: specifics */
$card-border: 1px solid $base-color-light;
$card-header-border-bottom-color: $base-color-light;
/* Table: Bulma override */
$table-cell-border: 1px solid $white-bis;
/* Table: specifics */
$table-avatar-size: $size-base * 1.5;
$table-avatar-size-mobile: 25vw;
/* Form */
$checkbox-border: 1px solid $base-color;
/* Modal card: Bulma override */
$modal-card-head-background-color: $white-ter;
$modal-card-title-size: $size-base;
$modal-card-body-padding: $default-padding 20px;
$modal-card-head-border-bottom: 1px solid $white-ter;
$modal-card-foot-border-top: 0;
/* Modal card: specifics */
$modal-card-width: 80vw;
$modal-card-width-mobile: 90vw;
$modal-card-foot-background-color: $white-ter;
/* Notification: Bulma override */
$notification-padding: $default-padding * 0.75 $default-padding;
/* Footer: Bulma override */
$footer-background-color: $white;
$footer-padding: $default-padding * 0.33 $default-padding;
/* Footer: specifics */
$footer-logo-height: $size-base * 2;
/* Progress: Bulma override */
$progress-bar-background-color: $grey-lighter;
/* Icon: specifics */
$icon-update-mark-size: $size-base * 0.5;
$icon-update-mark-color: $yellow;
$input-disabled-border-color: $grey-lighter;
$table-row-hover-background-color: hsl(0, 0%, 80%);
.menu-list {
div {
border-radius: $menu-item-radius;
color: $menu-item-color;
display: block;
padding: $menu-list-link-padding;
}
}

View File

@ -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)
*/
.is-tiles-wrapper {
margin-bottom: $default-padding;
}

View File

@ -0,0 +1,50 @@
/*
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)
*/
section.section.is-title-bar {
padding: $default-padding;
border-bottom: $light-border;
ul {
li {
display: inline-block;
padding: 0 $default-padding * 0.5 0 0;
font-size: $default-padding;
color: $title-bar-color;
&:after {
display: inline-block;
content: "/";
padding-left: $default-padding * 0.5;
}
&:last-child {
padding-right: 0;
font-weight: 900;
color: $title-bar-active-color;
&:after {
display: none;
}
}
}
}
}

View File

@ -0,0 +1,264 @@
.navcontainer:not(.default-navcontainer) {
margin-bottom: 0 !important;
}
.abort-button {
margin-left: 2px;
border: 2px solid rgb(0, 120, 231);
color: rgb(0, 120, 231);
font-size: 87%;
margin-top: 1px;
background: white;
}
div.pages-list {
margin-top: 15px;
}
.login-div,
.register-div {
display: block;
text-align: center;
}
a.page-number {
color: blue;
}
a.current-page-number {
color: inherit;
background-color: inherit;
}
.cancelled {
text-decoration: line-through;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* This CSS code styles the tab */
.tab {
overflow: hidden;
}
.logout {
float: right;
border: 20px;
margin-right: 15px;
margin-top: 15px;
}
.tab button {
background-color: lightgray;
color: black;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 18px 19px;
border: 2px solid #c1c1c1;
transition: 0.5s;
font-weight: bold;
}
.tab button:hover {
background-color: yellow;
border: 2px solid #c1c1c1;
color: black;
}
.tab button.active {
background-color: orange;
border: 2px solid #c1c1c1;
color: black;
font-weight: bold;
}
.tabcontent {
display: none;
padding: 8px 16px;
border: 2px solid #c1c1c1;
width: max-content;
}
.tabcontent.active {
display: block;
}
input[type="number"] {
-moz-appearance: textfield;
}
#transfer-fields {
display: flex;
flex-wrap: wrap;
}
#id_amount {
width: 6em;
display: inline-block;
border-radius: 4px 0px 0px 4px;
}
/**
* Amount without the currency,
* placed left to a .currency-indicator.
*/
#main .amount {
width: 6em;
display: inline-block;
border-radius: 4px 0px 0px 4px;
}
input {
background-color: inherit;
}
.large-amount {
font-weight: bold;
font-size: x-large;
}
.currency {
font-style: oblique;
}
/*
* Currency indicator to the right of input fields,
* with non-rounded corners to the left.
*/
#main .currency-indicator {
color: black;
border-radius: 0px 4px 4px 0px;
position: relative;
}
#main .fieldlabel {
display: block;
padding-bottom: 0.5em;
}
#main .fieldbox {
margin-right: 1em;
margin-bottom: 0.5em;
}
#logout-button {
display: block;
width: fit-content;
}
.register-form > .pure-form,
.login-form > .pure-form {
background: #4a4a4a;
color: #ffffff;
display: inline-block;
text-align: left;
margin-left: auto;
margin-right: auto;
padding: 16px 16px;
border-radius: 8px;
width: max-content;
.formFieldLabel {
margin: 2px 2px;
}
input[type="text"],
input[type="password"] {
border: none;
border-radius: 4px;
background: #6a6a6a;
color: #fefefe;
box-shadow: none;
}
input[placeholder="Password"][type="password"] {
margin-bottom: 8px;
}
.btn-register,
.btn-login {
float: left;
}
.btn-cancel {
float: right;
}
h2 {
margin-top: 0;
margin-bottom: 10px;
}
}
.challenge-div {
display: block;
text-align: center;
}
.challenge-form > .pure-form {
background: #4a4a4a;
color: #ffffff;
display: inline-block;
text-align: left;
margin-left: auto;
margin-right: auto;
padding: 16px 16px;
border-radius: 8px;
width: max-content;
.formFieldLabel {
margin: 2px 2px;
}
input[type="text"] {
border: none;
border-radius: 4px;
background: #6a6a6a;
color: #fefefe;
box-shadow: none;
}
.btn-confirm {
float: left;
}
.btn-cancel {
float: right;
}
h2 {
margin-top: 0;
margin-bottom: 10px;
}
}
.wire-transfer-form > .pure-form,
.payto-form > .pure-form,
.reserve-form > .pure-form {
background: #4a4a4a;
color: #ffffff;
display: inline-block;
text-align: left;
margin-left: auto;
margin-right: auto;
padding: 16px 16px;
border-radius: 8px;
width: max-content;
.formFieldLabel {
margin: 2px 2px;
}
input[type="text"] {
border: none;
border-radius: 4px;
background: #6a6a6a;
color: #fefefe;
box-shadow: none;
}
}
html {
background: #ffffff;
color: #2a2a2a;
}
.hint {
scale: 0.7;
}

View File

@ -0,0 +1,31 @@
nav,
nav a,
nav span,
.navcontainer,
nav button,
.demobar,
.navbtn {
color: white;
background: #a00000;
}
nav a.active,
nav button,
nav span.active,
.navbtn.active {
background-color: #7a0606;
}
nav a.active:hover,
nav span.active:hover,
.navbtn.active:hover,
nav button:hover,
nav a:hover,
nav span:hover,
.navbtn:hover {
background: #df3d3d;
}
nav a.navbtn.langbtn:focus {
background-color: #df3d3d;
}

View File

@ -0,0 +1,157 @@
@charset "UTF-8";
/*
Style common to all demo pages.
Colors:
- #1e2739 (dark blue)
- #0042b2 (default blue)
- #3daee9 (highlight blue)
*/
.demobar h1 {
text-align: center;
}
.demobar > p {
padding: 0.5em;
}
.demobar a,
.demobar a:visited {
color: inherit;
background-color: inherit;
}
.tt {
font-family: "Lucida Console", Monaco, monospace;
}
.informational-ok {
background: lightgreen;
border-radius: 1em;
padding: 0.5em;
}
.informational-fail {
background: lightpink;
border-radius: 1em;
padding: 0.5em;
}
.content {
margin-left: 2em;
overflow-x: auto;
}
.demobar {
overflow-x: auto;
background-color: #0042b2;
color: white;
}
body {
overflow-x: hidden;
overflow-y: auto;
}
.navcontainer {
background: #0042b2;
margin-bottom: 50px;
width: 100%;
color: white;
position: -webkit-sticky;
position: sticky;
top: 0px;
width: 100vw;
backdrop-filter: blur(10px);
opacity: 1;
z-index: 10000;
}
nav {
left: 1vw;
position: relative;
background: #0042b2;
z-index: 10000;
}
nav a,
nav button,
nav span,
.navbtn {
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
background: #0042b2;
height: inherit;
}
nav a,
nav button,
nav span,
.navbtn {
padding: 15px 32px;
}
nav a:hover,
nav span:hover,
.navbtn:hover {
background: #3daee9;
}
nav a.active,
nav span.active,
.navbtn.active {
background-color: #1e2739;
}
nav a.active:hover,
nav button.active:hover,
nav span.active:hover,
.navbtn.active:hover {
background: #3daee9;
}
nav a,
nav span,
.navbtn {
cursor: pointer;
}
nav .right {
float: right;
margin-right: 5vw;
}
nav .hide div.nav {
display: none;
}
// nav .right div.nav:hover {
// display: block;
// }
// nav .right:hover div.nav {
// display: block;
// }
.langbtn {
width: 100%;
text-align: left;
}
.skip {
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
.skip:focus {
position: static;
width: auto;
height: auto;
}

View File

@ -0,0 +1,22 @@
/*
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/>
*/
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(./XRXV3I6Li01BKofINeaE.ttf) format('truetype');
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
/*
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 "node_modules/bulma-radio/bulma-radio";
// @import "node_modules/bulma-responsive-tables/bulma-responsive-tables";
@import "node_modules/bulma-checkbox/bulma-checkbox";
// @import "node_modules/bulma-switch-control/bulma-switch-control";
// @import "node_modules/bulma-upload-control/bulma-upload-control";
/* Bulma */
@import "node_modules/bulma/bulma";

View File

@ -0,0 +1,4 @@
@import "pure";
@import "bank";
@import "demo";
@import "colors-bank";

Some files were not shown because too many files have changed in this diff Show More