fix #7714
This commit is contained in:
parent
f446a59214
commit
2d5fbb22cd
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
(C) 2022 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
|
||||
@ -13,7 +13,15 @@
|
||||
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} = {};
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
/*
|
||||
* Linaria need pre-process typscript files into javascript before running.
|
||||
* We choose to use the default preact-cli config.
|
||||
* This file should be used from @linaria/rollup plugin only
|
||||
*/
|
||||
{
|
||||
"plugins": ["./trim-extension.cjs"],
|
||||
}
|
151
packages/merchant-backend-ui/build.mjs
Executable file
151
packages/merchant-backend-ui/build.mjs
Executable file
@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021-2023 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 esbuild from "esbuild";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import linaria from '@linaria/esbuild'
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const BASE = process.cwd();
|
||||
|
||||
const preact = path.join(
|
||||
BASE,
|
||||
"node_modules",
|
||||
"preact",
|
||||
"compat",
|
||||
"dist",
|
||||
"compat.module.js",
|
||||
);
|
||||
|
||||
const preactCompatPlugin = {
|
||||
name: "preact-compat",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /^(react-dom|react)$/ }, (args) => {
|
||||
//console.log("onresolve", JSON.stringify(args, undefined, 2));
|
||||
return {
|
||||
path: preact,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const pages = ["OfferTip","OfferRefund","DepletedTip","RequestPayment","ShowOrderDetails"]
|
||||
const entryPoints = pages.map(p => `src/pages/${p}.tsx`);
|
||||
|
||||
let GIT_ROOT = BASE;
|
||||
while (!fs.existsSync(path.join(GIT_ROOT, ".git")) && GIT_ROOT !== "/") {
|
||||
GIT_ROOT = path.join(GIT_ROOT, "../");
|
||||
}
|
||||
if (GIT_ROOT === "/") {
|
||||
// eslint-disable-next-line no-undef
|
||||
console.log("not found");
|
||||
// eslint-disable-next-line no-undef
|
||||
process.exit(1);
|
||||
}
|
||||
const GIT_HASH = GIT_ROOT === "/" ? undefined : git_hash();
|
||||
|
||||
let _package = JSON.parse(fs.readFileSync(path.join(BASE, "package.json")));
|
||||
|
||||
function git_hash() {
|
||||
const rev = fs
|
||||
.readFileSync(path.join(GIT_ROOT, ".git", "HEAD"))
|
||||
.toString()
|
||||
.trim()
|
||||
.split(/.*[: ]/)
|
||||
.slice(-1)[0];
|
||||
if (rev.indexOf("/") === -1) {
|
||||
return rev;
|
||||
} else {
|
||||
return fs.readFileSync(path.join(GIT_ROOT, ".git", rev)).toString().trim();
|
||||
}
|
||||
}
|
||||
|
||||
function templatePlugin(options) {
|
||||
return {
|
||||
name: "template-backend",
|
||||
setup(build) {
|
||||
build.onEnd(() => {
|
||||
for (const page of options.pages) {
|
||||
const css = fs.readFileSync(path.join(build.initialOptions.outdir, `${page}.css`),"utf8").toString()
|
||||
const js = fs.readFileSync(path.join(build.initialOptions.outdir, `${page}.js`),"utf8").toString()
|
||||
const scripts = `<script>${js}</script>`
|
||||
const style = `<style>${css}</style>`
|
||||
const render = new Function(`${js}; return page.buildTimeRendering();`)()
|
||||
const html = `
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
${render.head}
|
||||
${style}
|
||||
</head>
|
||||
<script id="built_time_data">
|
||||
</script>
|
||||
<body>
|
||||
${render.body}
|
||||
${scripts}
|
||||
<script>page.mount()</script>
|
||||
</body>
|
||||
</html>`
|
||||
fs.writeFileSync(path.join(build.initialOptions.outdir, `${page}.html`), html);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const buildConfig = {
|
||||
entryPoints: [...entryPoints],
|
||||
bundle: true,
|
||||
outdir: "dist/pages",
|
||||
minify: true,
|
||||
loader: {
|
||||
".svg": "file",
|
||||
".png": "dataurl",
|
||||
".jpeg": "dataurl",
|
||||
'.ttf': 'file',
|
||||
'.woff': 'file',
|
||||
'.woff2': 'file',
|
||||
'.eot': 'file',
|
||||
},
|
||||
target: ["es6"],
|
||||
format: "iife",
|
||||
platform: "browser",
|
||||
sourcemap: false,
|
||||
globalName: "page",
|
||||
jsxFactory: "h",
|
||||
jsxFragment: "Fragment",
|
||||
define: {
|
||||
__VERSION__: `"${_package.version}"`,
|
||||
__GIT_HASH__: `"${GIT_HASH}"`,
|
||||
},
|
||||
plugins: [
|
||||
linaria.default({
|
||||
babelOptions: {
|
||||
babelrc: false,
|
||||
configFile: './babel.config-linaria.json',
|
||||
},
|
||||
sourceMap: true,
|
||||
}),
|
||||
preactCompatPlugin,
|
||||
templatePlugin({pages})
|
||||
],
|
||||
};
|
||||
|
||||
await esbuild.build(buildConfig)
|
@ -38,36 +38,18 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@gnu-taler/taler-util": "workspace:*",
|
||||
"axios": "^0.21.1",
|
||||
"date-fns": "^2.21.1",
|
||||
"history": "4.10.1",
|
||||
"jed": "^1.1.1",
|
||||
"preact": "10.11.3",
|
||||
"preact-router": "3.2.1",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"swr": "^0.5.5",
|
||||
"yup": "^0.32.9"
|
||||
"qrcode-generator": "^1.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.18.9",
|
||||
"@creativebulma/bulma-tooltip": "^1.2.0",
|
||||
"@gnu-taler/pogen": "^0.0.5",
|
||||
"@linaria/babel-preset": "3.0.0-beta.22",
|
||||
"@linaria/core": "3.0.0-beta.22",
|
||||
"@linaria/react": "3.0.0-beta.22",
|
||||
"@linaria/rollup": "3.0.0-beta.22",
|
||||
"@linaria/shaker": "3.0.0-beta.22",
|
||||
"@linaria/webpack-loader": "3.0.0-beta.22",
|
||||
"@rollup/plugin-alias": "^3.1.5",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^20.0.0",
|
||||
"@rollup/plugin-html": "^0.2.3",
|
||||
"@rollup/plugin-image": "^2.1.1",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-replace": "^3.0.0",
|
||||
"@rollup/plugin-typescript": "11",
|
||||
"@types/history": "^4.7.8",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"@types/mustache": "^4.1.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
@ -81,11 +63,8 @@
|
||||
"po2json": "^0.4.5",
|
||||
"preact-render-to-string": "^5.1.19",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-bundle-html": "^0.2.2",
|
||||
"rollup-plugin-css-only": "^3.1.0",
|
||||
"script-ext-html-webpack-plugin": "^2.1.5",
|
||||
"sirv-cli": "^1.0.11",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.9.4"
|
||||
}
|
||||
|
@ -1,116 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
// rollup.config.js
|
||||
import linaria from '@linaria/rollup';
|
||||
import nodeResolve from "@rollup/plugin-node-resolve";
|
||||
import alias from "@rollup/plugin-alias";
|
||||
import image from '@rollup/plugin-image';
|
||||
import json from "@rollup/plugin-json";
|
||||
import ts from "@rollup/plugin-typescript";
|
||||
import replace from "@rollup/plugin-replace";
|
||||
import css from 'rollup-plugin-css-only';
|
||||
import html from '@rollup/plugin-html';
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
|
||||
const template = async ({
|
||||
files,
|
||||
}) => {
|
||||
const scripts = (files.js || []).map(({ code }) => `<script>${code}</script>`).join('\n');
|
||||
const css = (files.css || []).map(({ source }) => `<style>${source}</style>`).join('\n');
|
||||
const ssr = (files.js || []).map(({ code }) => code).join('\n');
|
||||
const page = new Function(`${ssr}; return page.buildTimeRendering();`)()
|
||||
return `
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
${page.head}
|
||||
${css}
|
||||
</head>
|
||||
<script id="built_time_data">
|
||||
</script>
|
||||
<body>
|
||||
${page.body}
|
||||
${scripts}
|
||||
<script>page.mount()</script>
|
||||
</body>
|
||||
</html>`;
|
||||
};
|
||||
|
||||
const makePlugins = (name) => [
|
||||
alias({
|
||||
entries: [
|
||||
{ find: 'react', replacement: 'preact/compat' },
|
||||
{ find: 'react-dom', replacement: 'preact/compat' }
|
||||
]
|
||||
}),
|
||||
|
||||
replace({
|
||||
"process.env.NODE_ENV": JSON.stringify("production"),
|
||||
preventAssignment: true,
|
||||
}),
|
||||
|
||||
commonjs({
|
||||
include: [/node_modules/, /dist/],
|
||||
extensions: [".js"],
|
||||
ignoreGlobal: true,
|
||||
sourceMap: true,
|
||||
}),
|
||||
|
||||
nodeResolve({
|
||||
browser: true,
|
||||
preferBuiltins: true,
|
||||
}),
|
||||
|
||||
json(),
|
||||
image(),
|
||||
|
||||
linaria({
|
||||
sourceMap: process.env.NODE_ENV !== 'production',
|
||||
}),
|
||||
css(),
|
||||
ts({
|
||||
sourceMap: false,
|
||||
outputToFilesystem: false,
|
||||
}),
|
||||
html({ template, fileName: name }),
|
||||
];
|
||||
|
||||
function formatHtmlName(name) {
|
||||
return name
|
||||
.replace(/^[A-Z]/, letter => `${letter.toLowerCase()}`) //first letter lowercase
|
||||
.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`) //snake case
|
||||
.concat(".en.html"); //extension
|
||||
}
|
||||
|
||||
const pageDefinition = (name) => ({
|
||||
input: `src/pages/${name}.tsx`,
|
||||
output: {
|
||||
file: `dist/pages/${name}.js`,
|
||||
format: "iife",
|
||||
exports: 'named',
|
||||
name: 'page',
|
||||
},
|
||||
plugins: makePlugins(formatHtmlName(name)),
|
||||
});
|
||||
|
||||
export default [
|
||||
pageDefinition("OfferTip"),
|
||||
pageDefinition("OfferRefund"),
|
||||
pageDefinition("DepletedTip"),
|
||||
pageDefinition("RequestPayment"),
|
||||
pageDefinition("ShowOrderDetails"),
|
||||
]
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createContext, h, VNode } from 'preact'
|
||||
import { useCallback, useContext, useState } from 'preact/hooks'
|
||||
import { useBackendDefaultToken, useBackendURL } from '../hooks';
|
||||
|
||||
interface BackendContextType {
|
||||
url: string;
|
||||
token?: string;
|
||||
triedToLog: boolean;
|
||||
resetBackend: () => void;
|
||||
clearAllTokens: () => void;
|
||||
addTokenCleaner: (c: () => void) => void;
|
||||
updateLoginStatus: (url: string, token?: string) => void;
|
||||
}
|
||||
|
||||
const BackendContext = createContext<BackendContextType>({
|
||||
url: '',
|
||||
token: undefined,
|
||||
triedToLog: false,
|
||||
resetBackend: () => null,
|
||||
clearAllTokens: () => null,
|
||||
addTokenCleaner: () => null,
|
||||
updateLoginStatus: () => null,
|
||||
})
|
||||
|
||||
function useBackendContextState(defaultUrl?: string): BackendContextType {
|
||||
const [url, triedToLog, changeBackend, resetBackend] = useBackendURL(defaultUrl);
|
||||
const [token, _updateToken] = useBackendDefaultToken();
|
||||
const updateToken = (t?: string) => {
|
||||
_updateToken(t)
|
||||
}
|
||||
|
||||
const tokenCleaner = useCallback(() => { updateToken(undefined) }, [])
|
||||
const [cleaners, setCleaners] = useState([tokenCleaner])
|
||||
const addTokenCleaner = (c: () => void) => setCleaners(cs => [...cs, c])
|
||||
const addTokenCleanerMemo = useCallback((c: () => void) => { addTokenCleaner(c) }, [tokenCleaner])
|
||||
|
||||
const clearAllTokens = () => {
|
||||
cleaners.forEach(c => c())
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const k = localStorage.key(i)
|
||||
if (k && /^backend-token/.test(k)) localStorage.removeItem(k)
|
||||
}
|
||||
resetBackend()
|
||||
}
|
||||
|
||||
const updateLoginStatus = (url: string, token?: string) => {
|
||||
changeBackend(url);
|
||||
if (token) updateToken(token);
|
||||
};
|
||||
|
||||
|
||||
return { url, token, triedToLog, updateLoginStatus, resetBackend, clearAllTokens, addTokenCleaner: addTokenCleanerMemo }
|
||||
}
|
||||
|
||||
export const BackendContextProvider = ({ children, defaultUrl }: { children: any, defaultUrl?: string }): VNode => {
|
||||
const value = useBackendContextState(defaultUrl)
|
||||
|
||||
return h(BackendContext.Provider, { value, children });
|
||||
}
|
||||
|
||||
export const useBackendContext = (): BackendContextType => useContext(BackendContext);
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createContext } from 'preact'
|
||||
import { useContext } from 'preact/hooks'
|
||||
|
||||
interface Type {
|
||||
currency: string;
|
||||
version: string;
|
||||
}
|
||||
const Context = createContext<Type>(null!)
|
||||
|
||||
export const ConfigContextProvider = Context.Provider
|
||||
export const useConfigContext = (): Type => useContext(Context);
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { h, createContext, VNode, ComponentChildren } from 'preact'
|
||||
import { useContext } from 'preact/hooks'
|
||||
import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr';
|
||||
|
||||
interface Type {
|
||||
useSWR: typeof useSWR,
|
||||
useSWRInfinite: typeof useSWRInfinite,
|
||||
}
|
||||
|
||||
const Context = createContext<Type>({} as any)
|
||||
|
||||
export const useFetchContext = (): Type => useContext(Context);
|
||||
export const FetchContextProvider = ({ children }: { children: ComponentChildren }): VNode => {
|
||||
return h(Context.Provider, { value: { useSWR, useSWRInfinite }, children });
|
||||
}
|
||||
|
||||
export const FetchContextProviderTesting = ({ children, data }: { children: ComponentChildren, data:any }): VNode => {
|
||||
return h(Context.Provider, { value: { useSWR: () => data, useSWRInfinite }, children });
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createContext } from 'preact'
|
||||
import { useContext } from 'preact/hooks'
|
||||
|
||||
interface Type {
|
||||
id: string;
|
||||
token?: string;
|
||||
admin?: boolean;
|
||||
changeToken: (t?:string) => void;
|
||||
}
|
||||
|
||||
const Context = createContext<Type>({} as any)
|
||||
|
||||
export const InstanceContextProvider = Context.Provider
|
||||
export const useInstanceContext = (): Type => useContext(Context);
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createContext } from 'preact'
|
||||
import { useContext } from 'preact/hooks'
|
||||
|
||||
interface Type {
|
||||
id: string;
|
||||
token?: string;
|
||||
admin?: boolean;
|
||||
changeToken: (t?:string) => void;
|
||||
}
|
||||
|
||||
const Context = createContext<Type>({} as any)
|
||||
|
||||
export const ListenerContextProvider = Context.Provider
|
||||
export const useListenerContext = (): Type => useContext(Context);
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createContext, h, VNode } from 'preact'
|
||||
import { useContext, useEffect } from 'preact/hooks'
|
||||
import { useLang } from '../hooks'
|
||||
import * as jedLib from "jed";
|
||||
import { strings } from "../i18n/strings";
|
||||
|
||||
interface Type {
|
||||
lang: string;
|
||||
handler: any;
|
||||
changeLanguage: (l: string) => void;
|
||||
}
|
||||
const initial = {
|
||||
lang: 'en',
|
||||
handler: null,
|
||||
changeLanguage: () => {
|
||||
// do not change anything
|
||||
}
|
||||
}
|
||||
const Context = createContext<Type>(initial)
|
||||
|
||||
interface Props {
|
||||
initial?: string,
|
||||
children: any,
|
||||
forceLang?: string
|
||||
}
|
||||
|
||||
export const TranslationProvider = ({ initial, children, forceLang }: Props): VNode => {
|
||||
const [lang, changeLanguage] = useLang(initial)
|
||||
useEffect(() => {
|
||||
if (forceLang) {
|
||||
changeLanguage(forceLang)
|
||||
}
|
||||
})
|
||||
const handler = new jedLib.Jed(strings[lang]);
|
||||
return h(Context.Provider, { value: { lang, handler, changeLanguage }, children });
|
||||
}
|
||||
|
||||
export const useTranslationContext = (): Type => useContext(Context);
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
import { useState } from "preact/hooks";
|
||||
import { cancelPendingRequest } from "./backend";
|
||||
|
||||
export interface Options {
|
||||
slowTolerance: number,
|
||||
}
|
||||
|
||||
export interface AsyncOperationApi<T> {
|
||||
request: (...a: any) => void,
|
||||
cancel: () => void,
|
||||
data: T | undefined,
|
||||
isSlow: boolean,
|
||||
isLoading: boolean,
|
||||
error: string | undefined
|
||||
}
|
||||
|
||||
export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance: tooLong }: Options = { slowTolerance: 1000 }): AsyncOperationApi<T> {
|
||||
const [data, setData] = useState<T | undefined>(undefined);
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<any>(undefined);
|
||||
const [isSlow, setSlow] = useState(false)
|
||||
|
||||
const request = async (...args: any) => {
|
||||
if (!fn) return;
|
||||
setLoading(true);
|
||||
|
||||
const handler = setTimeout(() => {
|
||||
setSlow(true)
|
||||
}, tooLong)
|
||||
|
||||
try {
|
||||
const result = await fn(...args);
|
||||
setData(result);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
}
|
||||
setLoading(false);
|
||||
setSlow(false)
|
||||
clearTimeout(handler)
|
||||
};
|
||||
|
||||
function cancel() {
|
||||
cancelPendingRequest()
|
||||
setLoading(false);
|
||||
setSlow(false)
|
||||
}
|
||||
|
||||
return {
|
||||
request,
|
||||
cancel,
|
||||
data,
|
||||
isSlow,
|
||||
isLoading,
|
||||
error
|
||||
};
|
||||
}
|
@ -1,264 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { mutate, cache } from 'swr';
|
||||
import axios, { AxiosError, AxiosResponse } from 'axios'
|
||||
import { MerchantBackend } from '../declaration';
|
||||
import { useBackendContext } from '../context/backend';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
import { DEFAULT_REQUEST_TIMEOUT } from '../utils/constants';
|
||||
|
||||
export function mutateAll(re: RegExp, value?: unknown): Array<Promise<any>> {
|
||||
return cache.keys().filter(key => {
|
||||
return re.test(key)
|
||||
}).map(key => {
|
||||
return mutate(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
export type HttpResponse<T> = HttpResponseOk<T> | HttpResponseLoading<T> | HttpError;
|
||||
export type HttpResponsePaginated<T> = HttpResponseOkPaginated<T> | HttpResponseLoading<T> | HttpError;
|
||||
|
||||
export interface RequestInfo {
|
||||
url: string;
|
||||
hasToken: boolean;
|
||||
params: unknown;
|
||||
data: unknown;
|
||||
}
|
||||
|
||||
interface HttpResponseLoading<T> {
|
||||
ok?: false;
|
||||
loading: true;
|
||||
clientError?: false;
|
||||
serverError?: false;
|
||||
|
||||
data?: T;
|
||||
}
|
||||
export interface HttpResponseOk<T> {
|
||||
ok: true;
|
||||
loading?: false;
|
||||
clientError?: false;
|
||||
serverError?: false;
|
||||
|
||||
data: T;
|
||||
info?: RequestInfo;
|
||||
}
|
||||
|
||||
export type HttpResponseOkPaginated<T> = HttpResponseOk<T> & WithPagination
|
||||
|
||||
export interface WithPagination {
|
||||
loadMore: () => void;
|
||||
loadMorePrev: () => void;
|
||||
isReachingEnd?: boolean;
|
||||
isReachingStart?: boolean;
|
||||
}
|
||||
|
||||
export type HttpError = HttpResponseClientError | HttpResponseServerError | HttpResponseUnexpectedError;
|
||||
export interface SwrError {
|
||||
info: unknown,
|
||||
status: number,
|
||||
message: string,
|
||||
}
|
||||
export interface HttpResponseServerError {
|
||||
ok?: false;
|
||||
loading?: false;
|
||||
clientError?: false;
|
||||
serverError: true;
|
||||
|
||||
error?: MerchantBackend.ErrorDetail;
|
||||
status: number;
|
||||
message: string;
|
||||
info?: RequestInfo;
|
||||
}
|
||||
interface HttpResponseClientError {
|
||||
ok?: false;
|
||||
loading?: false;
|
||||
clientError: true;
|
||||
serverError?: false;
|
||||
|
||||
info?: RequestInfo;
|
||||
isUnauthorized: boolean;
|
||||
isNotfound: boolean;
|
||||
status: number;
|
||||
error?: MerchantBackend.ErrorDetail;
|
||||
message: string;
|
||||
|
||||
}
|
||||
|
||||
interface HttpResponseUnexpectedError {
|
||||
ok?: false;
|
||||
loading?: false;
|
||||
clientError?: false;
|
||||
serverError?: false;
|
||||
|
||||
info?: RequestInfo;
|
||||
status?: number;
|
||||
error: unknown;
|
||||
message: string;
|
||||
}
|
||||
|
||||
type Methods = 'get' | 'post' | 'patch' | 'delete' | 'put';
|
||||
|
||||
interface RequestOptions {
|
||||
method?: Methods;
|
||||
token?: string;
|
||||
data?: unknown;
|
||||
params?: unknown;
|
||||
}
|
||||
|
||||
function buildRequestOk<T>(res: AxiosResponse<T>, url: string, hasToken: boolean): HttpResponseOk<T> {
|
||||
return {
|
||||
ok: true, data: res.data, info: {
|
||||
params: res.config.params,
|
||||
data: res.config.data,
|
||||
url,
|
||||
hasToken,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// function buildResponse<T>(data?: T, error?: MerchantBackend.ErrorDetail, isValidating?: boolean): HttpResponse<T> {
|
||||
// if (isValidating) return {loading: true}
|
||||
// if (error) return buildRequestFailed()
|
||||
// }
|
||||
|
||||
function buildRequestFailed(ex: AxiosError<MerchantBackend.ErrorDetail>, url: string, hasToken: boolean): HttpResponseClientError | HttpResponseServerError | HttpResponseUnexpectedError {
|
||||
const status = ex.response?.status
|
||||
|
||||
const info: RequestInfo = {
|
||||
data: ex.request?.data,
|
||||
params: ex.request?.params,
|
||||
url,
|
||||
hasToken,
|
||||
};
|
||||
|
||||
if (status && status >= 400 && status < 500) {
|
||||
const error: HttpResponseClientError = {
|
||||
clientError: true,
|
||||
isNotfound: status === 404,
|
||||
isUnauthorized: status === 401,
|
||||
status,
|
||||
info,
|
||||
message: ex.response?.data?.hint || ex.message,
|
||||
error: ex.response?.data
|
||||
}
|
||||
return error
|
||||
}
|
||||
if (status && status >= 500 && status < 600) {
|
||||
const error: HttpResponseServerError = {
|
||||
serverError: true,
|
||||
status,
|
||||
info,
|
||||
message: `${ex.response?.data?.hint} (code ${ex.response?.data?.code})` || ex.message,
|
||||
error: ex.response?.data
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
const error: HttpResponseUnexpectedError = {
|
||||
info,
|
||||
status,
|
||||
error: ex,
|
||||
message: ex.message
|
||||
}
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
|
||||
const CancelToken = axios.CancelToken;
|
||||
let source = CancelToken.source();
|
||||
|
||||
export function cancelPendingRequest() {
|
||||
source.cancel('canceled by the user')
|
||||
source = CancelToken.source()
|
||||
}
|
||||
|
||||
let removeAxiosCancelToken = false
|
||||
/**
|
||||
* Jest mocking seems to break when using the cancelToken property.
|
||||
* Using this workaround when testing while finding the correct solution
|
||||
*/
|
||||
export function setAxiosRequestAsTestingEnvironment() {
|
||||
removeAxiosCancelToken = true
|
||||
}
|
||||
|
||||
export async function request<T>(url: string, options: RequestOptions = {}): Promise<HttpResponseOk<T>> {
|
||||
const headers = options.token ? { Authorization: `Bearer ${options.token}` } : undefined
|
||||
|
||||
try {
|
||||
const res = await axios({
|
||||
url,
|
||||
responseType: 'json',
|
||||
headers,
|
||||
cancelToken: !removeAxiosCancelToken ? source.token : undefined,
|
||||
method: options.method || 'get',
|
||||
data: options.data,
|
||||
params: options.params,
|
||||
timeout: DEFAULT_REQUEST_TIMEOUT * 1000,
|
||||
})
|
||||
return buildRequestOk<T>(res, url, !!options.token)
|
||||
} catch (e) {
|
||||
if (axios.isAxiosError(e)) {
|
||||
throw buildRequestFailed(e, url, !!options.token)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function fetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> {
|
||||
return request<T>(`${backend}${url}`, { token })
|
||||
}
|
||||
|
||||
export function useBackendInstancesTestForAdmin(): HttpResponse<MerchantBackend.Instances.InstancesResponse> {
|
||||
const { url, token } = useBackendContext()
|
||||
|
||||
type Type = MerchantBackend.Instances.InstancesResponse;
|
||||
|
||||
const [result, setResult] = useState<HttpResponse<Type>>({ loading: true })
|
||||
|
||||
useEffect(() => {
|
||||
request<Type>(`${url}/management/instances`, { token })
|
||||
.then(data => setResult(data))
|
||||
.catch(error => setResult(error))
|
||||
}, [url, token])
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
export function useBackendConfig(): HttpResponse<MerchantBackend.VersionResponse> {
|
||||
const { url, token } = useBackendContext()
|
||||
|
||||
type Type = MerchantBackend.VersionResponse;
|
||||
|
||||
const [result, setResult] = useState<HttpResponse<Type>>({ loading: true })
|
||||
|
||||
useEffect(() => {
|
||||
request<Type>(`${url}/config`, { token })
|
||||
.then(data => setResult(data))
|
||||
.catch(error => setResult(error))
|
||||
}, [url, token])
|
||||
|
||||
return result
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { StateUpdater, useCallback, useState } from "preact/hooks";
|
||||
import { ValueOrFunction } from '../utils/types';
|
||||
|
||||
|
||||
const calculateRootPath = () => {
|
||||
const rootPath = typeof window !== undefined ? window.location.origin + window.location.pathname : '/'
|
||||
return rootPath
|
||||
}
|
||||
|
||||
export function useBackendURL(url?: string): [string, boolean, StateUpdater<string>, () => void] {
|
||||
const [value, setter] = useNotNullLocalStorage('backend-url', url || calculateRootPath())
|
||||
const [triedToLog, setTriedToLog] = useLocalStorage('tried-login')
|
||||
|
||||
const checkedSetter = (v: ValueOrFunction<string>) => {
|
||||
setTriedToLog('yes')
|
||||
return setter(p => (v instanceof Function ? v(p) : v).replace(/\/$/, ''))
|
||||
}
|
||||
|
||||
const resetBackend = () => {
|
||||
setTriedToLog(undefined)
|
||||
}
|
||||
return [value, !!triedToLog, checkedSetter, resetBackend]
|
||||
}
|
||||
|
||||
export function useBackendDefaultToken(): [string | undefined, StateUpdater<string | undefined>] {
|
||||
return useLocalStorage('backend-token')
|
||||
}
|
||||
|
||||
export function useBackendInstanceToken(id: string): [string | undefined, StateUpdater<string | undefined>] {
|
||||
const [token, setToken] = useLocalStorage(`backend-token-${id}`)
|
||||
const [defaultToken, defaultSetToken] = useBackendDefaultToken()
|
||||
|
||||
// instance named 'default' use the default token
|
||||
if (id === 'default') {
|
||||
return [defaultToken, defaultSetToken]
|
||||
}
|
||||
|
||||
return [token, setToken]
|
||||
}
|
||||
|
||||
export function useLang(initial?: string): [string, StateUpdater<string>] {
|
||||
const browserLang = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined;
|
||||
const defaultLang = (browserLang || initial || 'en').substring(0, 2)
|
||||
return useNotNullLocalStorage('lang-preference', defaultLang)
|
||||
}
|
||||
|
||||
export function useLocalStorage(key: string, initialValue?: string): [string | undefined, StateUpdater<string | undefined>] {
|
||||
const [storedValue, setStoredValue] = useState<string | undefined>((): string | undefined => {
|
||||
return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
|
||||
});
|
||||
|
||||
const setValue = (value?: string | ((val?: string) => string | undefined)) => {
|
||||
setStoredValue(p => {
|
||||
const toStore = value instanceof Function ? value(p) : value
|
||||
if (typeof window !== "undefined") {
|
||||
if (!toStore) {
|
||||
window.localStorage.removeItem(key)
|
||||
} else {
|
||||
window.localStorage.setItem(key, toStore);
|
||||
}
|
||||
}
|
||||
return toStore
|
||||
})
|
||||
};
|
||||
|
||||
return [storedValue, setValue];
|
||||
}
|
||||
|
||||
export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] {
|
||||
const [storedValue, setStoredValue] = useState<string>((): string => {
|
||||
return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
|
||||
});
|
||||
|
||||
const setValue = (value: string | ((val: string) => string)) => {
|
||||
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
||||
setStoredValue(valueToStore);
|
||||
if (typeof window !== "undefined") {
|
||||
if (!valueToStore) {
|
||||
window.localStorage.removeItem(key)
|
||||
} else {
|
||||
window.localStorage.setItem(key, valueToStore);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return [storedValue, setValue];
|
||||
}
|
||||
|
||||
|
@ -1,187 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { MerchantBackend } from '../declaration';
|
||||
import { useBackendContext } from '../context/backend';
|
||||
import { fetcher, HttpError, HttpResponse, HttpResponseOk, request, SwrError } from './backend';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
import { useInstanceContext } from '../context/instance';
|
||||
|
||||
|
||||
interface InstanceAPI {
|
||||
updateInstance: (data: MerchantBackend.Instances.InstanceReconfigurationMessage) => Promise<void>;
|
||||
deleteInstance: () => Promise<void>;
|
||||
clearToken: () => Promise<void>;
|
||||
setNewToken: (token: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export function useManagementAPI(instanceId: string) : InstanceAPI {
|
||||
const { url, token } = useBackendContext()
|
||||
|
||||
const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => {
|
||||
await request(`${url}/management/instances/${instanceId}`, {
|
||||
method: 'patch',
|
||||
token,
|
||||
data: instance
|
||||
})
|
||||
|
||||
mutate([`/private/`, token, url], null)
|
||||
};
|
||||
|
||||
const deleteInstance = async (): Promise<void> => {
|
||||
await request(`${url}/management/instances/${instanceId}`, {
|
||||
method: 'delete',
|
||||
token,
|
||||
})
|
||||
|
||||
mutate([`/private/`, token, url], null)
|
||||
}
|
||||
|
||||
const clearToken = async (): Promise<void> => {
|
||||
await request(`${url}/management/instances/${instanceId}/auth`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data: { method: 'external' }
|
||||
})
|
||||
|
||||
mutate([`/private/`, token, url], null)
|
||||
}
|
||||
|
||||
const setNewToken = async (newToken: string): Promise<void> => {
|
||||
await request(`${url}/management/instances/${instanceId}/auth`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data: { method: 'token', token: newToken }
|
||||
})
|
||||
|
||||
mutate([`/private/`, token, url], null)
|
||||
}
|
||||
|
||||
return { updateInstance, deleteInstance, setNewToken, clearToken }
|
||||
}
|
||||
|
||||
export function useInstanceAPI(): InstanceAPI {
|
||||
const { url: baseUrl, token: adminToken } = useBackendContext()
|
||||
const { token: instanceToken, id, admin } = useInstanceContext()
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: adminToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
};
|
||||
|
||||
const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => {
|
||||
await request(`${url}/private/`, {
|
||||
method: 'patch',
|
||||
token,
|
||||
data: instance
|
||||
})
|
||||
|
||||
if (adminToken) mutate(['/private/instances', adminToken, baseUrl], null)
|
||||
mutate([`/private/`, token, url], null)
|
||||
};
|
||||
|
||||
const deleteInstance = async (): Promise<void> => {
|
||||
await request(`${url}/private/`, {
|
||||
method: 'delete',
|
||||
token: adminToken,
|
||||
})
|
||||
|
||||
if (adminToken) mutate(['/private/instances', adminToken, baseUrl], null)
|
||||
mutate([`/private/`, token, url], null)
|
||||
}
|
||||
|
||||
const clearToken = async (): Promise<void> => {
|
||||
await request(`${url}/private/auth`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data: { method: 'external' }
|
||||
})
|
||||
|
||||
mutate([`/private/`, token, url], null)
|
||||
}
|
||||
|
||||
const setNewToken = async (newToken: string): Promise<void> => {
|
||||
await request(`${url}/private/auth`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data: { method: 'token', token: newToken }
|
||||
})
|
||||
|
||||
mutate([`/private/`, token, url], null)
|
||||
}
|
||||
|
||||
return { updateInstance, deleteInstance, setNewToken, clearToken }
|
||||
}
|
||||
|
||||
|
||||
export function useInstanceDetails(): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: baseToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
}
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.QueryInstancesResponse>, HttpError>([`/private/`, token, url], fetcher, {
|
||||
refreshInterval:0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
errorRetryCount: 0,
|
||||
errorRetryInterval: 1,
|
||||
shouldRetryOnError: false,
|
||||
})
|
||||
|
||||
if (isValidating) return {loading:true, data: data?.data}
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return {loading: true}
|
||||
}
|
||||
|
||||
export function useManagedInstanceDetails(instanceId: string): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> {
|
||||
const { url, token } = useBackendContext();
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.QueryInstancesResponse>, HttpError>([`/management/instances/${instanceId}`, token, url], fetcher, {
|
||||
refreshInterval:0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
errorRetryCount: 0,
|
||||
errorRetryInterval: 1,
|
||||
shouldRetryOnError: false,
|
||||
})
|
||||
|
||||
if (isValidating) return {loading:true, data: data?.data}
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return {loading: true}
|
||||
}
|
||||
|
||||
export function useBackendInstances(): HttpResponse<MerchantBackend.Instances.InstancesResponse> {
|
||||
const { url } = useBackendContext()
|
||||
const { token } = useInstanceContext();
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.InstancesResponse>, HttpError>(['/management/instances', token, url], fetcher)
|
||||
|
||||
if (isValidating) return {loading:true, data: data?.data}
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return {loading: true}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { useState } from "preact/hooks";
|
||||
|
||||
/**
|
||||
* returns subscriber and activator
|
||||
* subscriber will receive a method (listener) that will be call when the activator runs.
|
||||
* the result of calling the listener will be sent to @action
|
||||
*
|
||||
* @param action from <T> to <R>
|
||||
* @returns activator and subscriber, undefined activator means that there is not subscriber
|
||||
*/
|
||||
|
||||
export function useListener<T, R = any>(action: (r: T) => Promise<R>): [undefined | (() => Promise<R>), (listener?: () => T) => void] {
|
||||
type RunnerHandler = { toBeRan?: () => Promise<R>; };
|
||||
const [state, setState] = useState<RunnerHandler>({});
|
||||
|
||||
/**
|
||||
* subscriber will receive a method that will be call when the activator runs
|
||||
*
|
||||
* @param listener function to be run when the activator runs
|
||||
*/
|
||||
const subscriber = (listener?: () => T) => {
|
||||
if (listener) {
|
||||
setState({
|
||||
toBeRan: () => {
|
||||
const whatWeGetFromTheListener = listener();
|
||||
return action(whatWeGetFromTheListener);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setState({
|
||||
toBeRan: undefined
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* activator will call runner if there is someone subscribed
|
||||
*/
|
||||
const activator = state.toBeRan ? async () => {
|
||||
if (state.toBeRan) {
|
||||
return state.toBeRan();
|
||||
}
|
||||
return Promise.reject();
|
||||
} : undefined;
|
||||
|
||||
return [activator, subscriber];
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { useCallback, useState } from "preact/hooks";
|
||||
import { Notification } from '../utils/types';
|
||||
|
||||
interface Result {
|
||||
notification?: Notification;
|
||||
pushNotification: (n: Notification) => void;
|
||||
removeNotification: () => void;
|
||||
}
|
||||
|
||||
export function useNotification(): Result {
|
||||
const [notification, setNotifications] = useState<Notification|undefined>(undefined)
|
||||
|
||||
const pushNotification = useCallback((n: Notification): void => {
|
||||
setNotifications(n)
|
||||
},[])
|
||||
|
||||
const removeNotification = useCallback(() => {
|
||||
setNotifications(undefined)
|
||||
},[])
|
||||
|
||||
return { notification, pushNotification, removeNotification }
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { useState } from "preact/hooks";
|
||||
import { Notification } from '../utils/types';
|
||||
|
||||
interface Result {
|
||||
notifications: Notification[];
|
||||
pushNotification: (n: Notification) => void;
|
||||
removeNotification: (n: Notification) => void;
|
||||
}
|
||||
|
||||
type NotificationWithDate = Notification & { since: Date }
|
||||
|
||||
export function useNotifications(initial: Notification[] = [], timeout = 3000): Result {
|
||||
const [notifications, setNotifications] = useState<(NotificationWithDate)[]>(initial.map(i => ({...i, since: new Date() })))
|
||||
|
||||
const pushNotification = (n: Notification): void => {
|
||||
const entry = { ...n, since: new Date() }
|
||||
setNotifications(ns => [...ns, entry])
|
||||
if (n.type !== 'ERROR') setTimeout(() => {
|
||||
setNotifications(ns => ns.filter(x => x.since !== entry.since))
|
||||
}, timeout)
|
||||
}
|
||||
|
||||
const removeNotification = (notif: Notification) => {
|
||||
setNotifications((ns: NotificationWithDate[]) => ns.filter(n => n !== notif))
|
||||
}
|
||||
return { notifications, pushNotification, removeNotification }
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
import useSWR from 'swr';
|
||||
import { useBackendContext } from '../context/backend';
|
||||
import { useInstanceContext } from '../context/instance';
|
||||
import { MerchantBackend } from '../declaration';
|
||||
import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants';
|
||||
import { fetcher, HttpError, HttpResponse, HttpResponseOk, HttpResponsePaginated, mutateAll, request } from './backend';
|
||||
|
||||
export interface OrderAPI {
|
||||
//FIXME: add OutOfStockResponse on 410
|
||||
createOrder: (data: MerchantBackend.Orders.PostOrderRequest) => Promise<HttpResponseOk<MerchantBackend.Orders.PostOrderResponse>>;
|
||||
forgetOrder: (id: string, data: MerchantBackend.Orders.ForgetRequest) => Promise<HttpResponseOk<void>>;
|
||||
refundOrder: (id: string, data: MerchantBackend.Orders.RefundRequest) => Promise<HttpResponseOk<MerchantBackend.Orders.MerchantRefundResponse>>;
|
||||
deleteOrder: (id: string) => Promise<HttpResponseOk<void>>;
|
||||
getPaymentURL: (id: string) => Promise<HttpResponseOk<string>>;
|
||||
}
|
||||
|
||||
type YesOrNo = 'yes' | 'no';
|
||||
|
||||
|
||||
export function orderFetcher<T>(url: string, token: string, backend: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, searchDate?: Date, delta?: number): Promise<HttpResponseOk<T>> {
|
||||
const date_ms = delta && delta < 0 && searchDate ? searchDate.getTime() + 1 : searchDate?.getTime()
|
||||
const params: any = {}
|
||||
if (paid !== undefined) params.paid = paid
|
||||
if (delta !== undefined) params.delta = delta
|
||||
if (refunded !== undefined) params.refunded = refunded
|
||||
if (wired !== undefined) params.wired = wired
|
||||
if (date_ms !== undefined) params.date_ms = date_ms
|
||||
return request<T>(`${backend}${url}`, { token, params })
|
||||
}
|
||||
|
||||
|
||||
export function useOrderAPI(): OrderAPI {
|
||||
const { url: baseUrl, token: adminToken } = useBackendContext()
|
||||
const { token: instanceToken, id, admin } = useInstanceContext()
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: adminToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
}
|
||||
|
||||
const createOrder = async (data: MerchantBackend.Orders.PostOrderRequest): Promise<HttpResponseOk<MerchantBackend.Orders.PostOrderResponse>> => {
|
||||
const res = await request<MerchantBackend.Orders.PostOrderResponse>(`${url}/private/orders`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data
|
||||
})
|
||||
await mutateAll(/@"\/private\/orders"@/)
|
||||
return res
|
||||
}
|
||||
const refundOrder = async (orderId: string, data: MerchantBackend.Orders.RefundRequest): Promise<HttpResponseOk<MerchantBackend.Orders.MerchantRefundResponse>> => {
|
||||
mutateAll(/@"\/private\/orders"@/)
|
||||
return request<MerchantBackend.Orders.MerchantRefundResponse>(`${url}/private/orders/${orderId}/refund`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data
|
||||
})
|
||||
|
||||
// return res
|
||||
}
|
||||
|
||||
const forgetOrder = async (orderId: string, data: MerchantBackend.Orders.ForgetRequest): Promise<HttpResponseOk<void>> => {
|
||||
mutateAll(/@"\/private\/orders"@/)
|
||||
return request(`${url}/private/orders/${orderId}/forget`, {
|
||||
method: 'patch',
|
||||
token,
|
||||
data
|
||||
})
|
||||
|
||||
}
|
||||
const deleteOrder = async (orderId: string): Promise<HttpResponseOk<void>> => {
|
||||
mutateAll(/@"\/private\/orders"@/)
|
||||
return request(`${url}/private/orders/${orderId}`, {
|
||||
method: 'delete',
|
||||
token
|
||||
})
|
||||
}
|
||||
|
||||
const getPaymentURL = async (orderId: string): Promise<HttpResponseOk<string>> => {
|
||||
return request<MerchantBackend.Orders.MerchantOrderStatusResponse>(`${url}/private/orders/${orderId}`, {
|
||||
method: 'get',
|
||||
token
|
||||
}).then((res) => {
|
||||
const url = res.data.order_status === "unpaid" ? res.data.taler_pay_uri : res.data.contract_terms.fulfillment_url
|
||||
const response: HttpResponseOk<string> = res as any
|
||||
response.data = url || ''
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
return { createOrder, forgetOrder, deleteOrder, refundOrder, getPaymentURL }
|
||||
}
|
||||
|
||||
export function useOrderDetails(oderId: string): HttpResponse<MerchantBackend.Orders.MerchantOrderStatusResponse> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: baseToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
};
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Orders.MerchantOrderStatusResponse>, HttpError>([`/private/orders/${oderId}`, token, url], fetcher, {
|
||||
refreshInterval: 0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
})
|
||||
|
||||
if (isValidating) return { loading: true, data: data?.data }
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return { loading: true }
|
||||
}
|
||||
|
||||
export interface InstanceOrderFilter {
|
||||
paid?: YesOrNo;
|
||||
refunded?: YesOrNo;
|
||||
wired?: YesOrNo;
|
||||
date?: Date;
|
||||
}
|
||||
|
||||
export function useInstanceOrders(args?: InstanceOrderFilter, updateFilter?: (d: Date) => void): HttpResponsePaginated<MerchantBackend.Orders.OrderHistory> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: baseToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
}
|
||||
|
||||
const [pageBefore, setPageBefore] = useState(1)
|
||||
const [pageAfter, setPageAfter] = useState(1)
|
||||
|
||||
const totalAfter = pageAfter * PAGE_SIZE;
|
||||
const totalBefore = args?.date ? pageBefore * PAGE_SIZE : 0;
|
||||
|
||||
/**
|
||||
* FIXME: this can be cleaned up a little
|
||||
*
|
||||
* the logic of double query should be inside the orderFetch so from the hook perspective and cache
|
||||
* is just one query and one error status
|
||||
*/
|
||||
const { data: beforeData, error: beforeError, isValidating: loadingBefore } = useSWR<HttpResponseOk<MerchantBackend.Orders.OrderHistory>, HttpError>(
|
||||
[`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, args?.date, totalBefore],
|
||||
orderFetcher,
|
||||
)
|
||||
const { data: afterData, error: afterError, isValidating: loadingAfter } = useSWR<HttpResponseOk<MerchantBackend.Orders.OrderHistory>, HttpError>(
|
||||
[`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, args?.date, -totalAfter],
|
||||
orderFetcher,
|
||||
)
|
||||
|
||||
//this will save last result
|
||||
const [lastBefore, setLastBefore] = useState<HttpResponse<MerchantBackend.Orders.OrderHistory>>({ loading: true })
|
||||
const [lastAfter, setLastAfter] = useState<HttpResponse<MerchantBackend.Orders.OrderHistory>>({ loading: true })
|
||||
useEffect(() => {
|
||||
if (afterData) setLastAfter(afterData)
|
||||
if (beforeData) setLastBefore(beforeData)
|
||||
}, [afterData, beforeData])
|
||||
|
||||
// this has problems when there are some ids missing
|
||||
|
||||
if (beforeError) return beforeError
|
||||
if (afterError) return afterError
|
||||
|
||||
|
||||
const pagination = {
|
||||
isReachingEnd: afterData && afterData.data.orders.length < totalAfter,
|
||||
isReachingStart: (!args?.date) || (beforeData && beforeData.data.orders.length < totalBefore),
|
||||
loadMore: () => {
|
||||
if (!afterData) return
|
||||
if (afterData.data.orders.length < MAX_RESULT_SIZE) {
|
||||
setPageAfter(pageAfter + 1)
|
||||
} else {
|
||||
const from = afterData.data.orders[afterData.data.orders.length - 1].timestamp.t_s
|
||||
if (from && updateFilter) updateFilter(new Date(from))
|
||||
}
|
||||
},
|
||||
loadMorePrev: () => {
|
||||
if (!beforeData) return
|
||||
if (beforeData.data.orders.length < MAX_RESULT_SIZE) {
|
||||
setPageBefore(pageBefore + 1)
|
||||
} else if (beforeData) {
|
||||
const from = beforeData.data.orders[beforeData.data.orders.length - 1].timestamp.t_s
|
||||
if (from && updateFilter) updateFilter(new Date(from))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const orders = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.orders.slice().reverse().concat((afterData || lastAfter).data.orders)
|
||||
if (loadingAfter || loadingBefore) return { loading: true, data: { orders } }
|
||||
if (beforeData && afterData) {
|
||||
return { ok: true, data: { orders }, ...pagination }
|
||||
}
|
||||
return { loading: true }
|
||||
|
||||
}
|
||||
|
@ -1,223 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { useEffect } from "preact/hooks";
|
||||
import useSWR, { trigger, useSWRInfinite, cache, mutate } from "swr";
|
||||
import { useBackendContext } from "../context/backend";
|
||||
// import { useFetchContext } from '../context/fetch';
|
||||
import { useInstanceContext } from "../context/instance";
|
||||
import { MerchantBackend, WithId } from "../declaration";
|
||||
import {
|
||||
fetcher,
|
||||
HttpError,
|
||||
HttpResponse,
|
||||
HttpResponseOk,
|
||||
mutateAll,
|
||||
request,
|
||||
} from "./backend";
|
||||
|
||||
export interface ProductAPI {
|
||||
createProduct: (
|
||||
data: MerchantBackend.Products.ProductAddDetail
|
||||
) => Promise<void>;
|
||||
updateProduct: (
|
||||
id: string,
|
||||
data: MerchantBackend.Products.ProductPatchDetail
|
||||
) => Promise<void>;
|
||||
deleteProduct: (id: string) => Promise<void>;
|
||||
lockProduct: (
|
||||
id: string,
|
||||
data: MerchantBackend.Products.LockRequest
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export function useProductAPI(): ProductAPI {
|
||||
const { url: baseUrl, token: adminToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin
|
||||
? {
|
||||
url: baseUrl,
|
||||
token: adminToken,
|
||||
}
|
||||
: {
|
||||
url: `${baseUrl}/instances/${id}`,
|
||||
token: instanceToken,
|
||||
};
|
||||
|
||||
const createProduct = async (
|
||||
data: MerchantBackend.Products.ProductAddDetail
|
||||
): Promise<void> => {
|
||||
await request(`${url}/private/products`, {
|
||||
method: "post",
|
||||
token,
|
||||
data,
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/products"@/, null);
|
||||
};
|
||||
|
||||
const updateProduct = async (
|
||||
productId: string,
|
||||
data: MerchantBackend.Products.ProductPatchDetail
|
||||
): Promise<void> => {
|
||||
const r = await request(`${url}/private/products/${productId}`, {
|
||||
method: "patch",
|
||||
token,
|
||||
data,
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/products\/.*"@/);
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const deleteProduct = async (productId: string): Promise<void> => {
|
||||
await request(`${url}/private/products/${productId}`, {
|
||||
method: "delete",
|
||||
token,
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/products"@/);
|
||||
};
|
||||
|
||||
const lockProduct = async (
|
||||
productId: string,
|
||||
data: MerchantBackend.Products.LockRequest
|
||||
): Promise<void> => {
|
||||
await request(`${url}/private/products/${productId}/lock`, {
|
||||
method: "post",
|
||||
token,
|
||||
data,
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/products"@/);
|
||||
};
|
||||
|
||||
return { createProduct, updateProduct, deleteProduct, lockProduct };
|
||||
}
|
||||
|
||||
export function useInstanceProducts(): HttpResponse<
|
||||
(MerchantBackend.Products.ProductDetail & WithId)[]
|
||||
> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
// const { useSWR, useSWRInfinite } = useFetchContext();
|
||||
|
||||
const { url, token } = !admin
|
||||
? {
|
||||
url: baseUrl,
|
||||
token: baseToken,
|
||||
}
|
||||
: {
|
||||
url: `${baseUrl}/instances/${id}`,
|
||||
token: instanceToken,
|
||||
};
|
||||
|
||||
const {
|
||||
data: list,
|
||||
error: listError,
|
||||
isValidating: listLoading,
|
||||
} = useSWR<
|
||||
HttpResponseOk<MerchantBackend.Products.InventorySummaryResponse>,
|
||||
HttpError
|
||||
>([`/private/products`, token, url], fetcher, {
|
||||
refreshInterval: 0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
});
|
||||
|
||||
const {
|
||||
data: products,
|
||||
error: productError,
|
||||
setSize,
|
||||
size,
|
||||
} = useSWRInfinite<
|
||||
HttpResponseOk<MerchantBackend.Products.ProductDetail>,
|
||||
HttpError
|
||||
>(
|
||||
(pageIndex: number) => {
|
||||
if (!list?.data || !list.data.products.length || listError || listLoading)
|
||||
return null;
|
||||
return [
|
||||
`/private/products/${list.data.products[pageIndex].product_id}`,
|
||||
token,
|
||||
url,
|
||||
];
|
||||
},
|
||||
fetcher,
|
||||
{
|
||||
revalidateAll: true,
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (list?.data && list.data.products.length > 0) {
|
||||
setSize(list.data.products.length);
|
||||
}
|
||||
}, [list?.data.products.length, listLoading]);
|
||||
|
||||
if (listLoading) return { loading: true, data: [] };
|
||||
if (listError) return listError;
|
||||
if (productError) return productError;
|
||||
if (list?.data && list.data.products.length === 0) {
|
||||
return { ok: true, data: [] };
|
||||
}
|
||||
if (products) {
|
||||
const dataWithId = products.map((d) => {
|
||||
//take the id from the queried url
|
||||
return {
|
||||
...d.data,
|
||||
id: d.info?.url.replace(/.*\/private\/products\//, "") || "",
|
||||
};
|
||||
});
|
||||
return { ok: true, data: dataWithId };
|
||||
}
|
||||
return { loading: true };
|
||||
}
|
||||
|
||||
export function useProductDetails(
|
||||
productId: string
|
||||
): HttpResponse<MerchantBackend.Products.ProductDetail> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin
|
||||
? {
|
||||
url: baseUrl,
|
||||
token: baseToken,
|
||||
}
|
||||
: {
|
||||
url: `${baseUrl}/instances/${id}`,
|
||||
token: instanceToken,
|
||||
};
|
||||
|
||||
const { data, error, isValidating } = useSWR<
|
||||
HttpResponseOk<MerchantBackend.Products.ProductDetail>,
|
||||
HttpError
|
||||
>([`/private/products/${productId}`, token, url], fetcher, {
|
||||
refreshInterval: 0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
});
|
||||
|
||||
if (isValidating) return { loading: true, data: data?.data };
|
||||
if (data) return data;
|
||||
if (error) return error;
|
||||
return { loading: true };
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import useSWR from 'swr';
|
||||
import { useBackendContext } from '../context/backend';
|
||||
import { useInstanceContext } from '../context/instance';
|
||||
import { MerchantBackend } from '../declaration';
|
||||
import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend';
|
||||
|
||||
|
||||
export function useReservesAPI(): ReserveMutateAPI {
|
||||
const { url: baseUrl, token: adminToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: adminToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
};
|
||||
|
||||
const createReserve = async (data: MerchantBackend.Tips.ReserveCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>> => {
|
||||
const res = await request<MerchantBackend.Tips.ReserveCreateConfirmation>(`${url}/private/reserves`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/reserves"@/);
|
||||
|
||||
return res
|
||||
};
|
||||
|
||||
const authorizeTipReserve = async (pub: string, data: MerchantBackend.Tips.TipCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => {
|
||||
const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(`${url}/private/reserves/${pub}/authorize-tip`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data
|
||||
});
|
||||
await mutateAll(/@"\/private\/reserves"@/);
|
||||
|
||||
return res
|
||||
};
|
||||
|
||||
const authorizeTip = async (data: MerchantBackend.Tips.TipCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => {
|
||||
const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(`${url}/private/tips`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/reserves"@/);
|
||||
|
||||
return res
|
||||
};
|
||||
|
||||
const deleteReserve = async (pub: string): Promise<HttpResponse<void>> => {
|
||||
const res = await request<void>(`${url}/private/reserves/${pub}`, {
|
||||
method: 'delete',
|
||||
token,
|
||||
});
|
||||
|
||||
await mutateAll(/@"\/private\/reserves"@/);
|
||||
|
||||
return res
|
||||
};
|
||||
|
||||
|
||||
return { createReserve, authorizeTip, authorizeTipReserve, deleteReserve };
|
||||
}
|
||||
|
||||
export interface ReserveMutateAPI {
|
||||
createReserve: (data: MerchantBackend.Tips.ReserveCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>>;
|
||||
authorizeTipReserve: (id: string, data: MerchantBackend.Tips.TipCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>;
|
||||
authorizeTip: (data: MerchantBackend.Tips.TipCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>;
|
||||
deleteReserve: (id: string) => Promise<HttpResponse<void>>;
|
||||
}
|
||||
|
||||
export function useInstanceTips(): HttpResponse<MerchantBackend.Tips.TippingReserveStatus> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: baseToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
}
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.TippingReserveStatus>, HttpError>([`/private/reserves`, token, url], fetcher)
|
||||
|
||||
if (isValidating) return { loading: true, data: data?.data }
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return { loading: true }
|
||||
}
|
||||
|
||||
|
||||
export function useReserveDetails(reserveId: string): HttpResponse<MerchantBackend.Tips.ReserveDetail> {
|
||||
const { url: baseUrl } = useBackendContext();
|
||||
const { token, id: instanceId, admin } = useInstanceContext();
|
||||
|
||||
const url = !admin ? baseUrl : `${baseUrl}/instances/${instanceId}`
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.ReserveDetail>, HttpError>([`/private/reserves/${reserveId}`, token, url], reserveDetailFetcher, {
|
||||
refreshInterval:0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
})
|
||||
|
||||
if (isValidating) return { loading: true, data: data?.data }
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return { loading: true }
|
||||
}
|
||||
|
||||
export function useTipDetails(tipId: string): HttpResponse<MerchantBackend.Tips.TipDetails> {
|
||||
const { url: baseUrl } = useBackendContext();
|
||||
const { token, id: instanceId, admin } = useInstanceContext();
|
||||
|
||||
const url = !admin ? baseUrl : `${baseUrl}/instances/${instanceId}`
|
||||
|
||||
const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.TipDetails>, HttpError>([`/private/tips/${tipId}`, token, url], tipsDetailFetcher, {
|
||||
refreshInterval:0,
|
||||
refreshWhenHidden: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshWhenOffline: false,
|
||||
})
|
||||
|
||||
if (isValidating) return { loading: true, data: data?.data }
|
||||
if (data) return data
|
||||
if (error) return error
|
||||
return { loading: true }
|
||||
}
|
||||
|
||||
export function reserveDetailFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> {
|
||||
return request<T>(`${backend}${url}`, { token, params: {
|
||||
tips: 'yes'
|
||||
} })
|
||||
}
|
||||
|
||||
export function tipsDetailFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> {
|
||||
return request<T>(`${backend}${url}`, { token, params: {
|
||||
pickups: 'yes'
|
||||
} })
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { MerchantBackend } from '../declaration';
|
||||
import { useBackendContext } from '../context/backend';
|
||||
import { request, mutateAll, HttpResponse, HttpError, HttpResponseOk, HttpResponsePaginated } from './backend';
|
||||
import useSWR from 'swr';
|
||||
import { useInstanceContext } from '../context/instance';
|
||||
import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
|
||||
async function transferFetcher<T>(url: string, token: string, backend: string, payto_uri?: string, verified?: string, position?: string, delta?: number): Promise<HttpResponseOk<T>> {
|
||||
const params: any = {}
|
||||
if (payto_uri !== undefined) params.payto_uri = payto_uri
|
||||
if (verified !== undefined) params.verified = verified
|
||||
if (delta !== undefined) {
|
||||
// if (delta > 0) {
|
||||
// params.after = searchDate?.getTime()
|
||||
// } else {
|
||||
// params.before = searchDate?.getTime()
|
||||
// }
|
||||
params.limit = delta
|
||||
}
|
||||
if (position !== undefined) params.offset = position
|
||||
|
||||
return request<T>(`${backend}${url}`, { token, params })
|
||||
}
|
||||
|
||||
export function useTransferAPI(): TransferAPI {
|
||||
const { url: baseUrl, token: adminToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: adminToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
};
|
||||
|
||||
const informTransfer = async (data: MerchantBackend.Transfers.TransferInformation): Promise<HttpResponseOk<MerchantBackend.Transfers.MerchantTrackTransferResponse>> => {
|
||||
mutateAll(/@"\/private\/transfers"@/);
|
||||
|
||||
return request<MerchantBackend.Transfers.MerchantTrackTransferResponse>(`${url}/private/transfers`, {
|
||||
method: 'post',
|
||||
token,
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
return { informTransfer };
|
||||
}
|
||||
|
||||
export interface TransferAPI {
|
||||
informTransfer: (data: MerchantBackend.Transfers.TransferInformation) => Promise<HttpResponseOk<MerchantBackend.Transfers.MerchantTrackTransferResponse>>;
|
||||
}
|
||||
|
||||
export interface InstanceTransferFilter {
|
||||
payto_uri?: string;
|
||||
verified?: 'yes' | 'no';
|
||||
position?: string;
|
||||
}
|
||||
|
||||
|
||||
export function useInstanceTransfers(args?: InstanceTransferFilter, updatePosition?: (id: string) => void): HttpResponsePaginated<MerchantBackend.Transfers.TransferList> {
|
||||
const { url: baseUrl, token: baseToken } = useBackendContext();
|
||||
const { token: instanceToken, id, admin } = useInstanceContext();
|
||||
|
||||
const { url, token } = !admin ? {
|
||||
url: baseUrl, token: baseToken
|
||||
} : {
|
||||
url: `${baseUrl}/instances/${id}`, token: instanceToken
|
||||
}
|
||||
|
||||
const [pageBefore, setPageBefore] = useState(1)
|
||||
const [pageAfter, setPageAfter] = useState(1)
|
||||
|
||||
const totalAfter = pageAfter * PAGE_SIZE;
|
||||
const totalBefore = args?.position !== undefined ? pageBefore * PAGE_SIZE : 0;
|
||||
|
||||
/**
|
||||
* FIXME: this can be cleaned up a little
|
||||
*
|
||||
* the logic of double query should be inside the orderFetch so from the hook perspective and cache
|
||||
* is just one query and one error status
|
||||
*/
|
||||
const { data: beforeData, error: beforeError, isValidating: loadingBefore } = useSWR<HttpResponseOk<MerchantBackend.Transfers.TransferList>, HttpError>(
|
||||
[`/private/transfers`, token, url, args?.payto_uri, args?.verified, args?.position, totalBefore],
|
||||
transferFetcher,
|
||||
)
|
||||
const { data: afterData, error: afterError, isValidating: loadingAfter } = useSWR<HttpResponseOk<MerchantBackend.Transfers.TransferList>, HttpError>(
|
||||
[`/private/transfers`, token, url, args?.payto_uri, args?.verified, args?.position, -totalAfter],
|
||||
transferFetcher,
|
||||
)
|
||||
|
||||
//this will save last result
|
||||
const [lastBefore, setLastBefore] = useState<HttpResponse<MerchantBackend.Transfers.TransferList>>({ loading: true })
|
||||
const [lastAfter, setLastAfter] = useState<HttpResponse<MerchantBackend.Transfers.TransferList>>({ loading: true })
|
||||
useEffect(() => {
|
||||
if (afterData) setLastAfter(afterData)
|
||||
if (beforeData) setLastBefore(beforeData)
|
||||
}, [afterData, beforeData])
|
||||
|
||||
// this has problems when there are some ids missing
|
||||
|
||||
if (beforeError) return beforeError
|
||||
if (afterError) return afterError
|
||||
|
||||
const pagination = {
|
||||
isReachingEnd: afterData && afterData.data.transfers.length < totalAfter,
|
||||
isReachingStart: (!args?.position) || (beforeData && beforeData.data.transfers.length < totalBefore),
|
||||
loadMore: () => {
|
||||
if (!afterData) return
|
||||
if (afterData.data.transfers.length < MAX_RESULT_SIZE) {
|
||||
setPageAfter(pageAfter + 1)
|
||||
} else {
|
||||
const from = `${afterData.data.transfers[afterData.data.transfers.length - 1].transfer_serial_id}`
|
||||
if (from && updatePosition) updatePosition(from)
|
||||
}
|
||||
},
|
||||
loadMorePrev: () => {
|
||||
if (!beforeData) return
|
||||
if (beforeData.data.transfers.length < MAX_RESULT_SIZE) {
|
||||
setPageBefore(pageBefore + 1)
|
||||
} else if (beforeData) {
|
||||
const from = `${beforeData.data.transfers[beforeData.data.transfers.length - 1].transfer_serial_id}`
|
||||
if (from && updatePosition) updatePosition(from)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const transfers = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.transfers.slice().reverse().concat((afterData || lastAfter).data.transfers)
|
||||
if (loadingAfter || loadingBefore) return { loading: true, data: { transfers } }
|
||||
if (beforeData && afterData) {
|
||||
return { ok: true, data: { transfers }, ...pagination }
|
||||
}
|
||||
return { loading: true }
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,203 +0,0 @@
|
||||
/*
|
||||
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>;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,27 +0,0 @@
|
||||
# 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"
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { BackendContextProvider } from "./context/backend";
|
||||
import { TranslationProvider } from "./context/translation";
|
||||
// import { Page as RequestPayment } from './RequestPayment';
|
||||
import { Route, Router } from "preact-router";
|
||||
import { Footer } from "./components/Footer";
|
||||
import "./css/pure-min.css";
|
||||
|
||||
export default function Application(): VNode {
|
||||
return (
|
||||
// <FetchContextProvider>
|
||||
<BackendContextProvider>
|
||||
<TranslationProvider>
|
||||
<ApplicationStatusRoutes />
|
||||
</TranslationProvider>
|
||||
</BackendContextProvider>
|
||||
// </FetchContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function ApplicationStatusRoutes(): VNode {
|
||||
return (
|
||||
<Fragment>
|
||||
<Router>
|
||||
<Route default component={() => <div>hello!</div>} />
|
||||
</Router>
|
||||
<Footer />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { amountFractionalBase, AmountJson, Amounts } from "@gnu-taler/taler-util";
|
||||
import { MerchantBackend } from "../declaration";
|
||||
|
||||
/**
|
||||
* sums two prices,
|
||||
* @param one
|
||||
* @param two
|
||||
* @returns
|
||||
*/
|
||||
const sumPrices = (one: string, two: string) => {
|
||||
const [currency, valueOne] = one.split(':')
|
||||
const [, valueTwo] = two.split(':')
|
||||
return `${currency}:${parseInt(valueOne, 10) + parseInt(valueTwo, 10)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* merge refund with the same description and a difference less than one minute
|
||||
* @param prev list of refunds that will hold the merged refunds
|
||||
* @param cur new refund to add to the list
|
||||
* @returns list with the new refund, may be merged with the last
|
||||
*/
|
||||
export function mergeRefunds(prev: MerchantBackend.Orders.RefundDetails[], cur: MerchantBackend.Orders.RefundDetails) {
|
||||
let tail;
|
||||
|
||||
if (prev.length === 0 || //empty list
|
||||
cur.timestamp.t_s === 'never' || //current does not have timestamp
|
||||
(tail = prev[prev.length - 1]).timestamp.t_s === 'never' || // last does not have timestamp
|
||||
cur.reason !== tail.reason || //different reason
|
||||
Math.abs(cur.timestamp.t_s - tail.timestamp.t_s) > 1000 * 60) {//more than 1 minute difference
|
||||
|
||||
prev.push(cur)
|
||||
return prev
|
||||
}
|
||||
|
||||
prev[prev.length - 1] = {
|
||||
...tail,
|
||||
amount: sumPrices(tail.amount, cur.amount)
|
||||
}
|
||||
|
||||
return prev
|
||||
}
|
||||
|
||||
export const rate = (one: string, two: string) => {
|
||||
const a = Amounts.parseOrThrow(one)
|
||||
const b = Amounts.parseOrThrow(two)
|
||||
const af = toFloat(a)
|
||||
const bf = toFloat(b)
|
||||
if (bf === 0) return 0
|
||||
return af / bf
|
||||
}
|
||||
|
||||
function toFloat(amount: AmountJson) {
|
||||
return amount.value + (amount.fraction / amountFractionalBase);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
//https://tools.ietf.org/html/rfc8905
|
||||
export const PAYTO_REGEX = /^payto:\/\/[a-zA-Z][a-zA-Z0-9-.]+(\/[a-zA-Z0-9\-\.\~\(\)@_%:!$&'*+,;=]*)*\??((amount|receiver-name|sender-name|instruction|message)=[a-zA-Z0-9\-\.\~\(\)@_%:!$'*+,;=]*&?)*$/
|
||||
export const PAYTO_WIRE_METHOD_LOOKUP = /payto:\/\/([a-zA-Z][a-zA-Z0-9-.]+)\/.*/
|
||||
|
||||
export const AMOUNT_REGEX = /^[a-zA-Z][a-zA-Z]*:[0-9][0-9,]*\.?[0-9,]*$/
|
||||
|
||||
export const INSTANCE_ID_LOOKUP = /^\/instances\/([^/]*)\/?$/
|
||||
|
||||
export const AMOUNT_ZERO_REGEX = /^[a-zA-Z][a-zA-Z]*:0$/
|
||||
|
||||
export const CROCKFORD_BASE32_REGEX = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]+[*~$=U]*$/
|
||||
|
||||
export const URL_REGEX = /^((https?:)(\/\/\/?)([\w]*(?::[\w]*)?@)?([\d\w\.-]+)(?::(\d+))?)\/$/
|
||||
|
||||
// how much rows we add every time user hit load more
|
||||
export const PAGE_SIZE = 20
|
||||
// how bigger can be the result set
|
||||
// after this threshold, load more with move the cursor
|
||||
export const MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1;
|
||||
|
||||
// how much we will wait for all request, in seconds
|
||||
export const DEFAULT_REQUEST_TIMEOUT = 10;
|
||||
|
||||
export const MAX_IMAGE_SIZE = 1024 * 1024;
|
||||
|
||||
export const INSTANCE_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.@-]+$/
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { WithId } from "../declaration";
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
export interface Actions<T extends WithId> {
|
||||
element: T;
|
||||
type: 'DELETE' | 'UPDATE';
|
||||
}
|
||||
|
||||
function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
|
||||
export function buildActions<T extends WithId>(instances: T[], selected: string[], action: 'DELETE'): Actions<T>[] {
|
||||
return selected.map(id => instances.find(i => i.id === id))
|
||||
.filter(notEmpty)
|
||||
.map(id => ({ element: id, type: action }))
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { VNode } from "preact"
|
||||
|
||||
export interface KeyValue {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface Notification {
|
||||
message: string;
|
||||
description?: string | VNode;
|
||||
type: MessageType;
|
||||
}
|
||||
|
||||
export type ValueOrFunction<T> = T | ((p: T) => T)
|
||||
export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS'
|
||||
|
23
packages/merchant-backend-ui/trim-extension.cjs
Normal file
23
packages/merchant-backend-ui/trim-extension.cjs
Normal file
@ -0,0 +1,23 @@
|
||||
// Simple plugin to trim extensions from the filename of relative import statements.
|
||||
// Required to get linaria to work with `moduleResulution: "Node16"` imports.
|
||||
// @author Florian Dold
|
||||
module.exports = function({ types: t }) {
|
||||
return {
|
||||
name: "trim-extension",
|
||||
visitor: {
|
||||
ImportDeclaration: (x) => {
|
||||
const src = x.node.source;
|
||||
if (src.value.startsWith(".")) {
|
||||
if (src.value.endsWith(".js")) {
|
||||
const newVal = src.value.replace(/[.]js$/, "")
|
||||
x.node.source = t.stringLiteral(newVal);
|
||||
}
|
||||
}
|
||||
if (src.value.endsWith(".jsx")) {
|
||||
const newVal = src.value.replace(/[.]jsx$/, "")
|
||||
x.node.source = t.stringLiteral(newVal);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
436
pnpm-lock.yaml
436
pnpm-lock.yaml
@ -175,83 +175,44 @@ importers:
|
||||
packages/merchant-backend-ui:
|
||||
specifiers:
|
||||
'@babel/core': 7.18.9
|
||||
'@creativebulma/bulma-tooltip': ^1.2.0
|
||||
'@gnu-taler/pogen': ^0.0.5
|
||||
'@gnu-taler/taler-util': workspace:*
|
||||
'@linaria/babel-preset': 3.0.0-beta.22
|
||||
'@linaria/core': 3.0.0-beta.22
|
||||
'@linaria/react': 3.0.0-beta.22
|
||||
'@linaria/rollup': 3.0.0-beta.22
|
||||
'@linaria/shaker': 3.0.0-beta.22
|
||||
'@linaria/webpack-loader': 3.0.0-beta.22
|
||||
'@rollup/plugin-alias': ^3.1.5
|
||||
'@rollup/plugin-babel': ^5.3.0
|
||||
'@rollup/plugin-commonjs': ^20.0.0
|
||||
'@rollup/plugin-html': ^0.2.3
|
||||
'@rollup/plugin-image': ^2.1.1
|
||||
'@rollup/plugin-json': ^4.1.0
|
||||
'@rollup/plugin-replace': ^3.0.0
|
||||
'@rollup/plugin-typescript': '11'
|
||||
'@types/history': ^4.7.8
|
||||
'@types/mocha': ^8.2.2
|
||||
'@types/mustache': ^4.1.2
|
||||
'@typescript-eslint/eslint-plugin': ^4.22.0
|
||||
'@typescript-eslint/parser': ^4.22.0
|
||||
axios: ^0.21.1
|
||||
babel-loader: ^8.2.2
|
||||
base64-inline-loader: ^1.1.1
|
||||
date-fns: ^2.21.1
|
||||
eslint: ^7.25.0
|
||||
eslint-config-preact: ^1.1.4
|
||||
eslint-plugin-header: ^3.1.1
|
||||
history: 4.10.1
|
||||
jed: ^1.1.1
|
||||
mustache: ^4.2.0
|
||||
po2json: ^0.4.5
|
||||
preact: 10.11.3
|
||||
preact-render-to-string: ^5.1.19
|
||||
preact-router: 3.2.1
|
||||
qrcode-generator: ^1.4.4
|
||||
rimraf: ^3.0.2
|
||||
rollup: ^2.56.3
|
||||
rollup-plugin-bundle-html: ^0.2.2
|
||||
rollup-plugin-css-only: ^3.1.0
|
||||
script-ext-html-webpack-plugin: ^2.1.5
|
||||
sirv-cli: ^1.0.11
|
||||
swr: ^0.5.5
|
||||
ts-node: ^10.9.1
|
||||
tslib: 2.4.0
|
||||
typescript: 4.9.4
|
||||
yup: ^0.32.9
|
||||
dependencies:
|
||||
'@gnu-taler/taler-util': link:../taler-util
|
||||
axios: 0.21.4
|
||||
date-fns: 2.29.3
|
||||
history: 4.10.1
|
||||
jed: 1.1.1
|
||||
preact: 10.11.3
|
||||
preact-router: 3.2.1_preact@10.11.3
|
||||
qrcode-generator: 1.4.4
|
||||
swr: 0.5.7
|
||||
yup: 0.32.11
|
||||
devDependencies:
|
||||
'@babel/core': 7.18.9
|
||||
'@creativebulma/bulma-tooltip': 1.2.0
|
||||
'@gnu-taler/pogen': link:../pogen
|
||||
'@linaria/babel-preset': 3.0.0-beta.22
|
||||
'@linaria/core': 3.0.0-beta.22
|
||||
'@linaria/react': 3.0.0-beta.22
|
||||
'@linaria/rollup': 3.0.0-beta.22
|
||||
'@linaria/shaker': 3.0.0-beta.22
|
||||
'@linaria/webpack-loader': 3.0.0-beta.22
|
||||
'@rollup/plugin-alias': 3.1.9_rollup@2.79.1
|
||||
'@rollup/plugin-babel': 5.3.1_cwbsg774jzhqoll5t2xfwyzz54
|
||||
'@rollup/plugin-commonjs': 20.0.0_rollup@2.79.1
|
||||
'@rollup/plugin-html': 0.2.4_rollup@2.79.1
|
||||
'@rollup/plugin-image': 2.1.1_rollup@2.79.1
|
||||
'@rollup/plugin-json': 4.1.0_rollup@2.79.1
|
||||
'@rollup/plugin-replace': 3.1.0_rollup@2.79.1
|
||||
'@rollup/plugin-typescript': 11.0.0_ds5km5eydjug3un6mvhihxeysu
|
||||
'@types/history': 4.7.11
|
||||
'@types/mocha': 8.2.3
|
||||
'@types/mustache': 4.2.1
|
||||
'@typescript-eslint/eslint-plugin': 4.33.0_thyv6urrmcfyirt6hwk42bhgva
|
||||
@ -265,11 +226,8 @@ importers:
|
||||
po2json: 0.4.5
|
||||
preact-render-to-string: 5.2.6_preact@10.11.3
|
||||
rimraf: 3.0.2
|
||||
rollup: 2.79.1
|
||||
rollup-plugin-bundle-html: 0.2.2
|
||||
rollup-plugin-css-only: 3.1.0_rollup@2.79.1
|
||||
script-ext-html-webpack-plugin: 2.1.5
|
||||
sirv-cli: 1.0.14
|
||||
ts-node: 10.9.1_typescript@4.9.4
|
||||
tslib: 2.4.0
|
||||
typescript: 4.9.4
|
||||
|
||||
@ -3040,6 +2998,13 @@ packages:
|
||||
resolution: {integrity: sha512-ooImbeXEBxf77cttbzA7X5rC5aAWm9UsXIGViFOnsqB+6M944GkB28S5R4UWRqjFd2iW4zGEkEifAU+q43pt2w==}
|
||||
dev: true
|
||||
|
||||
/@cspotcode/source-map-support/0.8.1:
|
||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
dev: true
|
||||
|
||||
/@emotion/is-prop-valid/0.8.8:
|
||||
resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
|
||||
dependencies:
|
||||
@ -3378,6 +3343,13 @@ packages:
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/@jridgewell/trace-mapping/0.3.9:
|
||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.0
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/@leichtgewicht/ip-codec/2.0.4:
|
||||
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
|
||||
dev: true
|
||||
@ -3479,16 +3451,6 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@linaria/rollup/3.0.0-beta.22:
|
||||
resolution: {integrity: sha512-VSMOvDsuAC/GoIwt111v6T7NlK5xvwVi5sK6OUNBCAZLdBai72uPKQKniye6qLMsI9SUfzPbktjTPVP/Uffweg==}
|
||||
engines: {node: ^12.16.0 || >=13.7.0}
|
||||
dependencies:
|
||||
'@linaria/babel-preset': 3.0.0-beta.22
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@linaria/shaker/3.0.0-beta.22:
|
||||
resolution: {integrity: sha512-NOi71i/XfBJpBOT5eepRvv6B64IMdjsKwv+vxLW+IuFHx3wnqXgZsgimNK2qoXbpqy9xWsSEeB/4QA4m8GCUKQ==}
|
||||
engines: {node: ^12.16.0 || >=13.7.0}
|
||||
@ -3696,33 +3658,6 @@ packages:
|
||||
webpack: 4.46.0
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-alias/3.1.9_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0
|
||||
dependencies:
|
||||
rollup: 2.79.1
|
||||
slash: 3.0.0
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-babel/5.3.1_cwbsg774jzhqoll5t2xfwyzz54:
|
||||
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
'@types/babel__core': ^7.1.9
|
||||
rollup: ^1.20.0||^2.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/babel__core':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/core': 7.18.9
|
||||
'@babel/helper-module-imports': 7.18.6
|
||||
'@rollup/pluginutils': 3.1.0_rollup@2.79.1
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-babel/5.3.1_vyv4jbhmcriklval33ak5sngky:
|
||||
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@ -3740,51 +3675,6 @@ packages:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-commonjs/20.0.0_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-5K0g5W2Ol8hAcTHqcTBHiA7M58tfmYi1o9KxeJuuRNpGaTa5iLjcyemBitCBcKXaHamOBBEH2dGom6v6Unmqjg==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.38.3
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 3.1.0_rollup@2.79.1
|
||||
commondir: 1.0.1
|
||||
estree-walker: 2.0.2
|
||||
glob: 7.2.3
|
||||
is-reference: 1.2.1
|
||||
magic-string: 0.25.9
|
||||
resolve: 1.22.1
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-html/0.2.4_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-x0qpNXxbmGa9Jnl4OX89AORPe2T/a4DqNK69BGRnEdaPKq6MdiUXSTam/eCkF5DxkQGcRcPq0L4vzr/E3q4mVA==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0
|
||||
dependencies:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-image/2.1.1_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-AgP4U85zuQJdUopLUCM+hTf45RepgXeTb8EJsleExVy99dIoYpt3ZlDYJdKmAc2KLkNntCDg6BPJvgJU3uGF+g==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0 || ^2.0.0
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 3.1.0_rollup@2.79.1
|
||||
mini-svg-data-uri: 1.4.4
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-json/4.1.0_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0 || ^2.0.0
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 3.1.0_rollup@2.79.1
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-node-resolve/11.2.1_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@ -3810,36 +3700,6 @@ packages:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-replace/3.1.0_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-pA3XRUrSKybVYqmH5TqWNZpGxF+VV+1GrYchKgCNIj2vsSOX7CVm2RCtx8p2nrC7xvkziYyK+lSi74T93MU3YA==}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0 || ^2.0.0
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 3.1.0_rollup@2.79.1
|
||||
magic-string: 0.25.9
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-typescript/11.0.0_ds5km5eydjug3un6mvhihxeysu:
|
||||
resolution: {integrity: sha512-goPyCWBiimk1iJgSTgsehFD5OOFHiAknrRJjqFCudcW8JtWiBlK284Xnn4flqMqg6YAjVG/EE+3aVzrL5qNSzQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.14.0||^3.0.0
|
||||
tslib: '*'
|
||||
typescript: '>=3.7.0'
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
tslib:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.0.2_rollup@2.79.1
|
||||
resolve: 1.22.1
|
||||
rollup: 2.79.1
|
||||
tslib: 2.4.0
|
||||
typescript: 4.9.4
|
||||
dev: true
|
||||
|
||||
/@rollup/pluginutils/3.1.0_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
@ -3852,29 +3712,6 @@ packages:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/pluginutils/4.2.1:
|
||||
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
dependencies:
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 2.3.1
|
||||
dev: true
|
||||
|
||||
/@rollup/pluginutils/5.0.2_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/estree': 1.0.0
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 2.3.1
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@sindresorhus/is/0.14.0:
|
||||
resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
|
||||
engines: {node: '>=6'}
|
||||
@ -3901,6 +3738,22 @@ packages:
|
||||
engines: {node: '>=10.13.0'}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node10/1.0.9:
|
||||
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node12/1.0.11:
|
||||
resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node14/1.0.3:
|
||||
resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node16/1.0.3:
|
||||
resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
|
||||
dev: true
|
||||
|
||||
/@types/body-parser/1.19.2:
|
||||
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
|
||||
dependencies:
|
||||
@ -3941,10 +3794,6 @@ packages:
|
||||
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
|
||||
dev: true
|
||||
|
||||
/@types/estree/1.0.0:
|
||||
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
|
||||
dev: true
|
||||
|
||||
/@types/express-serve-static-core/4.17.31:
|
||||
resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==}
|
||||
dependencies:
|
||||
@ -4886,6 +4735,10 @@ packages:
|
||||
resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
|
||||
dev: true
|
||||
|
||||
/arg/4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
dev: true
|
||||
|
||||
/argparse/1.0.10:
|
||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
dependencies:
|
||||
@ -5233,6 +5086,7 @@ packages:
|
||||
follow-redirects: 1.15.2
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: true
|
||||
|
||||
/axios/0.27.2:
|
||||
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||
@ -5834,7 +5688,7 @@ packages:
|
||||
minipass-pipeline: 1.2.4
|
||||
mkdirp: 1.0.4
|
||||
p-map: 4.0.0
|
||||
promise-inflight: 1.0.1_bluebird@3.7.2
|
||||
promise-inflight: 1.0.1
|
||||
rimraf: 3.0.2
|
||||
ssri: 8.0.1
|
||||
tar: 6.1.11
|
||||
@ -6029,30 +5883,6 @@ packages:
|
||||
/check-error/1.0.2:
|
||||
resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
|
||||
|
||||
/cheerio-select/2.1.0:
|
||||
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
css-select: 5.1.0
|
||||
css-what: 6.1.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
dev: true
|
||||
|
||||
/cheerio/1.0.0-rc.12:
|
||||
resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
cheerio-select: 2.1.0
|
||||
dom-serializer: 2.0.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
htmlparser2: 8.0.1
|
||||
parse5: 7.1.1
|
||||
parse5-htmlparser2-tree-adapter: 7.0.0
|
||||
dev: true
|
||||
|
||||
/chokidar/2.1.8:
|
||||
resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
|
||||
deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
|
||||
@ -6598,6 +6428,10 @@ packages:
|
||||
sha.js: 2.4.11
|
||||
dev: true
|
||||
|
||||
/create-require/1.1.1:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
dev: true
|
||||
|
||||
/critters-webpack-plugin/2.5.0_html-webpack-plugin@3.2.0:
|
||||
resolution: {integrity: sha512-O41TSPV2orAfrV6kSVC0SivZCtVkeypCNKb7xtrbqE/CfjrHeRaFaGuxglcjOI2IGf+oNg6E+ZoOktdlhXPTIQ==}
|
||||
peerDependencies:
|
||||
@ -6729,16 +6563,6 @@ packages:
|
||||
nth-check: 2.1.1
|
||||
dev: true
|
||||
|
||||
/css-select/5.1.0:
|
||||
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
css-what: 6.1.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
nth-check: 2.1.1
|
||||
dev: true
|
||||
|
||||
/css-tree/1.0.0-alpha.37:
|
||||
resolution: {integrity: sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@ -7158,11 +6982,6 @@ packages:
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: true
|
||||
|
||||
/dequal/2.0.2:
|
||||
resolution: {integrity: sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/des.js/1.0.1:
|
||||
resolution: {integrity: sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==}
|
||||
dependencies:
|
||||
@ -7179,6 +6998,11 @@ packages:
|
||||
resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
|
||||
dev: true
|
||||
|
||||
/diff/4.0.2:
|
||||
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
dev: true
|
||||
|
||||
/diff/5.0.0:
|
||||
resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
@ -7245,14 +7069,6 @@ packages:
|
||||
entities: 2.2.0
|
||||
dev: true
|
||||
|
||||
/dom-serializer/2.0.0:
|
||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
entities: 4.4.0
|
||||
dev: true
|
||||
|
||||
/domain-browser/1.2.0:
|
||||
resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==}
|
||||
engines: {node: '>=0.4', npm: '>=1.2'}
|
||||
@ -7279,13 +7095,6 @@ packages:
|
||||
domelementtype: 2.3.0
|
||||
dev: true
|
||||
|
||||
/domhandler/5.0.3:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
dev: true
|
||||
|
||||
/domutils/1.7.0:
|
||||
resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
|
||||
dependencies:
|
||||
@ -7301,14 +7110,6 @@ packages:
|
||||
domhandler: 4.3.1
|
||||
dev: true
|
||||
|
||||
/domutils/3.0.1:
|
||||
resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
|
||||
dependencies:
|
||||
dom-serializer: 2.0.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
dev: true
|
||||
|
||||
/dot-prop/5.3.0:
|
||||
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
|
||||
engines: {node: '>=8'}
|
||||
@ -7462,11 +7263,6 @@ packages:
|
||||
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
|
||||
dev: true
|
||||
|
||||
/entities/4.4.0:
|
||||
resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==}
|
||||
engines: {node: '>=0.12'}
|
||||
dev: true
|
||||
|
||||
/envinfo/7.8.1:
|
||||
resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==}
|
||||
engines: {node: '>=4'}
|
||||
@ -8257,10 +8053,6 @@ packages:
|
||||
resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
|
||||
dev: true
|
||||
|
||||
/estree-walker/2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
dev: true
|
||||
|
||||
/esutils/2.0.3:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -9209,13 +9001,6 @@ packages:
|
||||
minimalistic-assert: 1.0.1
|
||||
dev: true
|
||||
|
||||
/hasha/4.0.1:
|
||||
resolution: {integrity: sha512-+wnvroCn3pq0CAKWfItGPyl0DJOob2qs/2D/Rh0a/O90LBzmo5GaKHwIRb6FInVvmEl1mCIHL5RqlfTLvh6FoQ==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
is-stream: 1.1.0
|
||||
dev: true
|
||||
|
||||
/hasha/5.2.2:
|
||||
resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==}
|
||||
engines: {node: '>=8'}
|
||||
@ -9352,15 +9137,6 @@ packages:
|
||||
entities: 2.2.0
|
||||
dev: true
|
||||
|
||||
/htmlparser2/8.0.1:
|
||||
resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
entities: 4.4.0
|
||||
dev: true
|
||||
|
||||
/http-cache-semantics/4.1.0:
|
||||
resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==}
|
||||
dev: true
|
||||
@ -9880,12 +9656,6 @@ packages:
|
||||
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
|
||||
dev: true
|
||||
|
||||
/is-reference/1.2.1:
|
||||
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
|
||||
dependencies:
|
||||
'@types/estree': 1.0.0
|
||||
dev: true
|
||||
|
||||
/is-regex/1.1.4:
|
||||
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -9909,11 +9679,6 @@ packages:
|
||||
call-bind: 1.0.2
|
||||
dev: true
|
||||
|
||||
/is-stream/1.1.0:
|
||||
resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/is-stream/2.0.1:
|
||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||
engines: {node: '>=8'}
|
||||
@ -10546,6 +10311,10 @@ packages:
|
||||
semver: 6.3.0
|
||||
dev: true
|
||||
|
||||
/make-error/1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
dev: true
|
||||
|
||||
/map-age-cleaner/0.1.3:
|
||||
resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==}
|
||||
engines: {node: '>=6'}
|
||||
@ -10744,11 +10513,6 @@ packages:
|
||||
webpack-sources: 1.4.3
|
||||
dev: true
|
||||
|
||||
/mini-svg-data-uri/1.4.4:
|
||||
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/minimalistic-assert/1.0.1:
|
||||
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
|
||||
dev: true
|
||||
@ -11630,13 +11394,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/parse5-htmlparser2-tree-adapter/7.0.0:
|
||||
resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
parse5: 7.1.1
|
||||
dev: true
|
||||
|
||||
/parse5/4.0.0:
|
||||
resolution: {integrity: sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==}
|
||||
dev: true
|
||||
@ -11645,12 +11402,6 @@ packages:
|
||||
resolution: {integrity: sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==}
|
||||
dev: true
|
||||
|
||||
/parse5/7.1.1:
|
||||
resolution: {integrity: sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==}
|
||||
dependencies:
|
||||
entities: 4.4.0
|
||||
dev: true
|
||||
|
||||
/parseurl/1.3.3:
|
||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@ -12661,6 +12412,15 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: true
|
||||
|
||||
/promise-inflight/1.0.1:
|
||||
resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
|
||||
peerDependencies:
|
||||
bluebird: '*'
|
||||
peerDependenciesMeta:
|
||||
bluebird:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/promise-inflight/1.0.1_bluebird@3.7.2:
|
||||
resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
|
||||
peerDependencies:
|
||||
@ -13215,23 +12975,6 @@ packages:
|
||||
inherits: 2.0.4
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-bundle-html/0.2.2:
|
||||
resolution: {integrity: sha512-nK4Z/k3MVjfCcnC5T15ksHw3JyRJx110oduy3VBW0ki2qI0tu4pLlgXyltBgtd+gpiFCPqEnfy89XRPG+eCOwA==}
|
||||
dependencies:
|
||||
cheerio: 1.0.0-rc.12
|
||||
hasha: 4.0.1
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-css-only/3.1.0_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA==}
|
||||
engines: {node: '>=10.12.0'}
|
||||
peerDependencies:
|
||||
rollup: 1 || 2
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/rollup-plugin-terser/7.0.2_rollup@2.79.1:
|
||||
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
|
||||
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
|
||||
@ -13364,18 +13107,6 @@ packages:
|
||||
ajv-keywords: 5.1.0_ajv@8.11.0
|
||||
dev: true
|
||||
|
||||
/script-ext-html-webpack-plugin/2.1.5:
|
||||
resolution: {integrity: sha512-nMjd5dtsnoB8dS+pVM9ZL4mC9O1uVtTxrDS99OGZsZxFbkZE6pw0HCMued/cncDrKivIShO9vwoyOTvsGqQHEQ==}
|
||||
engines: {node: '>=6.11.5'}
|
||||
peerDependencies:
|
||||
html-webpack-plugin: ^3.0.0 || ^4.0.0
|
||||
webpack: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/select-hose/2.0.0:
|
||||
resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==}
|
||||
dev: true
|
||||
@ -14178,14 +13909,6 @@ packages:
|
||||
stable: 0.1.8
|
||||
dev: true
|
||||
|
||||
/swr/0.5.7:
|
||||
resolution: {integrity: sha512-Jh1Efgu8nWZV9rU4VLUMzBzcwaZgi4znqbVXvAtUy/0JzSiN6bNjLaJK8vhY/Rtp7a83dosz5YuehfBNwC/ZoQ==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0
|
||||
dependencies:
|
||||
dequal: 2.0.2
|
||||
dev: false
|
||||
|
||||
/swr/1.3.0:
|
||||
resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==}
|
||||
peerDependencies:
|
||||
@ -14493,6 +14216,36 @@ packages:
|
||||
tslib: 2.4.1
|
||||
dev: true
|
||||
|
||||
/ts-node/10.9.1_typescript@4.9.4:
|
||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.9
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.3
|
||||
acorn: 8.8.1
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 4.9.4
|
||||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-pnp/1.2.0_typescript@4.6.4:
|
||||
resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
|
||||
engines: {node: '>=6'}
|
||||
@ -14926,6 +14679,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/v8-compile-cache-lib/3.0.1:
|
||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||
dev: true
|
||||
|
||||
/v8-compile-cache/2.3.0:
|
||||
resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
|
||||
dev: true
|
||||
@ -15696,6 +15453,11 @@ packages:
|
||||
yargs-parser: 21.1.1
|
||||
dev: true
|
||||
|
||||
/yn/3.1.1:
|
||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/yocto-queue/0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
Loading…
Reference in New Issue
Block a user