summaryrefslogtreecommitdiff
path: root/bank/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'bank/index.js')
-rw-r--r--bank/index.js13088
1 files changed, 6635 insertions, 6453 deletions
diff --git a/bank/index.js b/bank/index.js
index b92517709..077e9190e 100644
--- a/bank/index.js
+++ b/bank/index.js
@@ -10200,14 +10200,14 @@ var TalerProtocolTimestamp;
})(TalerProtocolTimestamp || (TalerProtocolTimestamp = {}));
var timeshift = 0;
var Duration;
-(function(Duration4) {
+(function(Duration2) {
function toMilliseconds(d5) {
if (d5.d_ms === "forever") {
return Number.MAX_VALUE;
}
return d5.d_ms;
}
- Duration4.toMilliseconds = toMilliseconds;
+ Duration2.toMilliseconds = toMilliseconds;
function getRemaining(deadline, now = AbsoluteTime.now()) {
if (deadline.t_ms === "never") {
return { d_ms: "forever" };
@@ -10220,7 +10220,7 @@ var Duration;
}
return { d_ms: deadline.t_ms - now.t_ms };
}
- Duration4.getRemaining = getRemaining;
+ Duration2.getRemaining = getRemaining;
function fromPrettyString(s5) {
let dMs = 0;
let currentNum = "";
@@ -10261,7 +10261,7 @@ var Duration;
d_ms: dMs
};
}
- Duration4.fromPrettyString = fromPrettyString;
+ Duration2.fromPrettyString = fromPrettyString;
function cmp(d1, d22) {
if (d1.d_ms === "forever") {
if (d22.d_ms === "forever") {
@@ -10280,35 +10280,45 @@ var Duration;
}
return -1;
}
- Duration4.cmp = cmp;
+ Duration2.cmp = cmp;
function max(d1, d22) {
return durationMax(d1, d22);
}
- Duration4.max = max;
+ Duration2.max = max;
function min(d1, d22) {
return durationMin(d1, d22);
}
- Duration4.min = min;
+ Duration2.min = min;
function multiply(d1, n2) {
return durationMul(d1, n2);
}
- Duration4.multiply = multiply;
+ Duration2.multiply = multiply;
function toIntegerYears(d5) {
if (typeof d5.d_ms !== "number") {
throw Error("infinite duration");
}
return Math.ceil(d5.d_ms / 1e3 / 60 / 60 / 24 / 365);
}
- Duration4.toIntegerYears = toIntegerYears;
- Duration4.fromSpec = durationFromSpec;
+ Duration2.toIntegerYears = toIntegerYears;
+ function fromSpec(spec) {
+ let d_ms = 0;
+ d_ms += (spec.seconds ?? 0) * SECONDS;
+ d_ms += (spec.minutes ?? 0) * MINUTES;
+ d_ms += (spec.hours ?? 0) * HOURS;
+ d_ms += (spec.days ?? 0) * DAYS;
+ d_ms += (spec.months ?? 0) * MONTHS;
+ d_ms += (spec.years ?? 0) * YEARS;
+ return { d_ms };
+ }
+ Duration2.fromSpec = fromSpec;
function getForever() {
return { d_ms: "forever" };
}
- Duration4.getForever = getForever;
+ Duration2.getForever = getForever;
function getZero() {
return { d_ms: 0 };
}
- Duration4.getZero = getZero;
+ Duration2.getZero = getZero;
function fromTalerProtocolDuration(d5) {
if (d5.d_us === "forever") {
return {
@@ -10319,7 +10329,7 @@ var Duration;
d_ms: Math.floor(d5.d_us / 1e3)
};
}
- Duration4.fromTalerProtocolDuration = fromTalerProtocolDuration;
+ Duration2.fromTalerProtocolDuration = fromTalerProtocolDuration;
function toTalerProtocolDuration(d5) {
if (d5.d_ms === "forever") {
return {
@@ -10330,49 +10340,49 @@ var Duration;
d_us: d5.d_ms * 1e3
};
}
- Duration4.toTalerProtocolDuration = toTalerProtocolDuration;
+ Duration2.toTalerProtocolDuration = toTalerProtocolDuration;
function fromMilliseconds(ms) {
return {
d_ms: ms
};
}
- Duration4.fromMilliseconds = fromMilliseconds;
+ Duration2.fromMilliseconds = fromMilliseconds;
function clamp(args) {
return durationMax(durationMin(args.value, args.upper), args.lower);
}
- Duration4.clamp = clamp;
+ Duration2.clamp = clamp;
})(Duration || (Duration = {}));
var AbsoluteTime;
-(function(AbsoluteTime3) {
+(function(AbsoluteTime4) {
function getStampMsNow() {
return (/* @__PURE__ */ new Date()).getTime();
}
- AbsoluteTime3.getStampMsNow = getStampMsNow;
+ AbsoluteTime4.getStampMsNow = getStampMsNow;
function getStampMsNever() {
return Number.MAX_SAFE_INTEGER;
}
- AbsoluteTime3.getStampMsNever = getStampMsNever;
+ AbsoluteTime4.getStampMsNever = getStampMsNever;
function now() {
return {
t_ms: (/* @__PURE__ */ new Date()).getTime() + timeshift,
[opaque_AbsoluteTime]: true
};
}
- AbsoluteTime3.now = now;
+ AbsoluteTime4.now = now;
function never() {
return {
t_ms: "never",
[opaque_AbsoluteTime]: true
};
}
- AbsoluteTime3.never = never;
+ AbsoluteTime4.never = never;
function fromMilliseconds(ms) {
return {
t_ms: ms,
[opaque_AbsoluteTime]: true
};
}
- AbsoluteTime3.fromMilliseconds = fromMilliseconds;
+ AbsoluteTime4.fromMilliseconds = fromMilliseconds;
function cmp(t1, t22) {
if (t1.t_ms === "never") {
if (t22.t_ms === "never") {
@@ -10391,7 +10401,7 @@ var AbsoluteTime;
}
return -1;
}
- AbsoluteTime3.cmp = cmp;
+ AbsoluteTime4.cmp = cmp;
function min(t1, t22) {
if (t1.t_ms === "never") {
return { t_ms: t22.t_ms, [opaque_AbsoluteTime]: true };
@@ -10401,7 +10411,7 @@ var AbsoluteTime;
}
return { t_ms: Math.min(t1.t_ms, t22.t_ms), [opaque_AbsoluteTime]: true };
}
- AbsoluteTime3.min = min;
+ AbsoluteTime4.min = min;
function max(t1, t22) {
if (t1.t_ms === "never") {
return { t_ms: "never", [opaque_AbsoluteTime]: true };
@@ -10411,7 +10421,7 @@ var AbsoluteTime;
}
return { t_ms: Math.max(t1.t_ms, t22.t_ms), [opaque_AbsoluteTime]: true };
}
- AbsoluteTime3.max = max;
+ AbsoluteTime4.max = max;
function difference(t1, t22) {
if (t1.t_ms === "never") {
return { d_ms: "forever" };
@@ -10421,15 +10431,15 @@ var AbsoluteTime;
}
return { d_ms: Math.abs(t1.t_ms - t22.t_ms) };
}
- AbsoluteTime3.difference = difference;
+ AbsoluteTime4.difference = difference;
function isExpired(t4) {
return cmp(t4, now()) <= 0;
}
- AbsoluteTime3.isExpired = isExpired;
+ AbsoluteTime4.isExpired = isExpired;
function isNever(t4) {
return t4.t_ms === "never";
}
- AbsoluteTime3.isNever = isNever;
+ AbsoluteTime4.isNever = isNever;
function fromProtocolTimestamp(t4) {
if (t4.t_s === "never") {
return { t_ms: "never", [opaque_AbsoluteTime]: true };
@@ -10439,14 +10449,14 @@ var AbsoluteTime;
[opaque_AbsoluteTime]: true
};
}
- AbsoluteTime3.fromProtocolTimestamp = fromProtocolTimestamp;
+ AbsoluteTime4.fromProtocolTimestamp = fromProtocolTimestamp;
function fromStampMs(stampMs) {
return {
t_ms: stampMs,
[opaque_AbsoluteTime]: true
};
}
- AbsoluteTime3.fromStampMs = fromStampMs;
+ AbsoluteTime4.fromStampMs = fromStampMs;
function fromPreciseTimestamp(t4) {
if (t4.t_s === "never") {
return { t_ms: "never", [opaque_AbsoluteTime]: true };
@@ -10457,14 +10467,14 @@ var AbsoluteTime;
[opaque_AbsoluteTime]: true
};
}
- AbsoluteTime3.fromPreciseTimestamp = fromPreciseTimestamp;
+ AbsoluteTime4.fromPreciseTimestamp = fromPreciseTimestamp;
function toStampMs(at2) {
if (at2.t_ms === "never") {
return Number.MAX_SAFE_INTEGER;
}
return at2.t_ms;
}
- AbsoluteTime3.toStampMs = toStampMs;
+ AbsoluteTime4.toStampMs = toStampMs;
function toPreciseTimestamp(at2) {
if (at2.t_ms == "never") {
return {
@@ -10478,7 +10488,7 @@ var AbsoluteTime;
off_us
};
}
- AbsoluteTime3.toPreciseTimestamp = toPreciseTimestamp;
+ AbsoluteTime4.toPreciseTimestamp = toPreciseTimestamp;
function toProtocolTimestamp(at2) {
if (at2.t_ms === "never") {
return { t_s: "never" };
@@ -10487,7 +10497,7 @@ var AbsoluteTime;
t_s: Math.floor(at2.t_ms / 1e3)
};
}
- AbsoluteTime3.toProtocolTimestamp = toProtocolTimestamp;
+ AbsoluteTime4.toProtocolTimestamp = toProtocolTimestamp;
function isBetween(t4, start, end) {
if (cmp(t4, start) < 0) {
return false;
@@ -10497,7 +10507,7 @@ var AbsoluteTime;
}
return true;
}
- AbsoluteTime3.isBetween = isBetween;
+ AbsoluteTime4.isBetween = isBetween;
function toIsoString(t4) {
if (t4.t_ms === "never") {
return "<never>";
@@ -10505,14 +10515,14 @@ var AbsoluteTime;
return new Date(t4.t_ms).toISOString();
}
}
- AbsoluteTime3.toIsoString = toIsoString;
+ AbsoluteTime4.toIsoString = toIsoString;
function addDuration(t1, d5) {
if (t1.t_ms === "never" || d5.d_ms === "forever") {
return { t_ms: "never", [opaque_AbsoluteTime]: true };
}
return { t_ms: t1.t_ms + d5.d_ms, [opaque_AbsoluteTime]: true };
}
- AbsoluteTime3.addDuration = addDuration;
+ AbsoluteTime4.addDuration = addDuration;
function remaining(t1) {
if (t1.t_ms === "never") {
return Duration.getForever();
@@ -10523,7 +10533,7 @@ var AbsoluteTime;
}
return Duration.fromMilliseconds(Math.max(0, t1.t_ms - stampNow.t_ms));
}
- AbsoluteTime3.remaining = remaining;
+ AbsoluteTime4.remaining = remaining;
function subtractDuraction(t1, d5) {
if (t1.t_ms === "never") {
return { t_ms: "never", [opaque_AbsoluteTime]: true };
@@ -10533,14 +10543,14 @@ var AbsoluteTime;
}
return { t_ms: Math.max(0, t1.t_ms - d5.d_ms), [opaque_AbsoluteTime]: true };
}
- AbsoluteTime3.subtractDuraction = subtractDuraction;
+ AbsoluteTime4.subtractDuraction = subtractDuraction;
function stringify(t4) {
if (t4.t_ms === "never") {
return "never";
}
return new Date(t4.t_ms).toISOString();
}
- AbsoluteTime3.stringify = stringify;
+ AbsoluteTime4.stringify = stringify;
})(AbsoluteTime || (AbsoluteTime = {}));
var SECONDS = 1e3;
var MINUTES = SECONDS * 60;
@@ -10548,16 +10558,6 @@ var HOURS = MINUTES * 60;
var DAYS = HOURS * 24;
var MONTHS = DAYS * 30;
var YEARS = DAYS * 365;
-function durationFromSpec(spec) {
- let d_ms = 0;
- d_ms += (spec.seconds ?? 0) * SECONDS;
- d_ms += (spec.minutes ?? 0) * MINUTES;
- d_ms += (spec.hours ?? 0) * HOURS;
- d_ms += (spec.days ?? 0) * DAYS;
- d_ms += (spec.months ?? 0) * MONTHS;
- d_ms += (spec.years ?? 0) * YEARS;
- return { d_ms };
-}
function durationMin(d1, d22) {
if (d1.d_ms === "forever") {
return { d_ms: d22.d_ms };
@@ -11422,10 +11422,12 @@ var paytoPfx = "payto://";
function buildPayto(type, first, second) {
switch (type) {
case "bitcoin": {
+ const uppercased = first.toUpperCase();
const result = {
isKnown: true,
targetType: "bitcoin",
targetPath: first,
+ address: uppercased,
params: {},
segwitAddrs: !second ? [] : generateFakeSegwitAddress(second, first)
};
@@ -11524,10 +11526,12 @@ function parsePaytoUri(s5) {
const msg = /\b([A-Z0-9]{52})\b/.exec(params["message"]);
const reserve = !msg ? params["subject"] : msg[0];
const segwitAddrs = !reserve ? [] : generateFakeSegwitAddress(reserve, targetPath);
+ const uppercased = targetType.toUpperCase();
const result = {
isKnown: true,
targetPath,
targetType,
+ address: uppercased,
params,
segwitAddrs
};
@@ -11542,14 +11546,14 @@ function parsePaytoUri(s5) {
}
// ../taler-util/lib/taleruri.js
-function codecForTalerActionString() {
+function codecForTalerUriString() {
return {
decode(x6, c4) {
if (typeof x6 !== "string") {
throw new DecodingError(`expected string at ${renderContext(c4)} but got ${typeof x6}`);
}
if (parseTalerUri(x6) === void 0) {
- throw new DecodingError(`invalid taler action at ${renderContext(c4)} but got "${x6}"`);
+ throw new DecodingError(`invalid taler URI at ${renderContext(c4)} but got "${x6}"`);
}
return x6;
}
@@ -11927,8 +11931,7 @@ function getUrlInfo(baseUrl, params = {}) {
var codecForAccessToken = codecForString;
var codecForTokenSuccessResponse = () => buildCodecForObject().property("access_token", codecForAccessToken()).property("expiration", codecForTimestamp).build("TalerAuthentication.TokenSuccessResponse");
var codecForCurrencySpecificiation = () => buildCodecForObject().property("name", codecForString()).property("num_fractional_input_digits", codecForNumber()).property("num_fractional_normal_digits", codecForNumber()).property("num_fractional_trailing_zero_digits", codecForNumber()).property("alt_unit_names", codecForMap(codecForString())).build("CurrencySpecification");
-var codecForIntegrationBankConfig = () => buildCodecForObject().property("name", codecForConstString("taler-bank-integration")).property("version", codecForString()).property("currency", codecForString()).property("currency_specification", codecForCurrencySpecificiation()).build("TalerCorebankApi.IntegrationConfig");
-var codecForCoreBankConfig = () => buildCodecForObject().property("name", codecForConstString("libeufin-bank")).property("version", codecForString()).property("allow_conversion", codecForBoolean()).property("allow_registrations", codecForBoolean()).property("allow_deletions", codecForBoolean()).property("allow_edit_name", codecForBoolean()).property("allow_edit_cashout_payto_uri", codecForBoolean()).property("default_debit_threshold", codecForAmountString()).property("currency", codecForString()).property("currency_specification", codecForCurrencySpecificiation()).property("supported_tan_channels", codecForList(codecForEither(codecForConstString(TalerCorebankApi.TanChannel.SMS), codecForConstString(TalerCorebankApi.TanChannel.EMAIL)))).property("wire_type", codecForString()).build("TalerCorebankApi.Config");
+var codecForCoreBankConfig = () => buildCodecForObject().property("name", codecForConstString("libeufin-bank")).property("version", codecForString()).property("bank_name", codecForString()).property("allow_conversion", codecForBoolean()).property("allow_registrations", codecForBoolean()).property("allow_deletions", codecForBoolean()).property("allow_edit_name", codecForBoolean()).property("allow_edit_cashout_payto_uri", codecForBoolean()).property("default_debit_threshold", codecForAmountString()).property("currency", codecForString()).property("currency_specification", codecForCurrencySpecificiation()).property("supported_tan_channels", codecForList(codecForEither(codecForConstString(TalerCorebankApi.TanChannel.SMS), codecForConstString(TalerCorebankApi.TanChannel.EMAIL)))).property("wire_type", codecForString()).build("TalerCorebankApi.Config");
var codecForBalance = () => buildCodecForObject().property("amount", codecForAmountString()).property("credit_debit_indicator", codecForEither(codecForConstString("credit"), codecForConstString("debit"))).build("TalerCorebankApi.Balance");
var codecForPublicAccount = () => buildCodecForObject().property("username", codecForString()).property("balance", codecForBalance()).property("payto_uri", codecForPaytoString()).property("is_taler_exchange", codecForBoolean()).property("row_id", codecOptional(codecForNumber())).build("TalerCorebankApi.PublicAccount");
var codecForPublicAccountsResponse = () => buildCodecForObject().property("public_accounts", codecForList(codecForPublicAccount())).build("TalerCorebankApi.PublicAccountsResponse");
@@ -11941,7 +11944,7 @@ var codecForBankAccountTransactionsResponse = () => buildCodecForObject().proper
var codecForBankAccountTransactionInfo = () => buildCodecForObject().property("creditor_payto_uri", codecForPaytoString()).property("debtor_payto_uri", codecForPaytoString()).property("amount", codecForAmountString()).property("direction", codecForEither(codecForConstString("debit"), codecForConstString("credit"))).property("subject", codecForString()).property("row_id", codecForNumber()).property("date", codecForTimestamp).build("TalerCorebankApi.BankAccountTransactionInfo");
var codecForCreateTransactionResponse = () => buildCodecForObject().property("row_id", codecForNumber()).build("TalerCorebankApi.CreateTransactionResponse");
var codecForRegisterAccountResponse = () => buildCodecForObject().property("internal_payto_uri", codecForPaytoString()).build("TalerCorebankApi.RegisterAccountResponse");
-var codecForBankAccountCreateWithdrawalResponse = () => buildCodecForObject().property("taler_withdraw_uri", codecForTalerActionString()).property("withdrawal_id", codecForString()).build("TalerCorebankApi.BankAccountCreateWithdrawalResponse");
+var codecForBankAccountCreateWithdrawalResponse = () => buildCodecForObject().property("taler_withdraw_uri", codecForTalerUriString()).property("withdrawal_id", codecForString()).build("TalerCorebankApi.BankAccountCreateWithdrawalResponse");
var codecForCashoutPending = () => buildCodecForObject().property("cashout_id", codecForNumber()).build("TalerCorebankApi.CashoutPending");
var codecForCashoutConversionResponse = () => buildCodecForObject().property("amount_credit", codecForAmountString()).property("amount_debit", codecForAmountString()).build("TalerCorebankApi.CashoutConversionResponse");
var codecForCashinConversionResponse = () => buildCodecForObject().property("amount_credit", codecForAmountString()).property("amount_debit", codecForAmountString()).build("TalerCorebankApi.CashinConversionResponse");
@@ -11953,26 +11956,13 @@ var codecForCashoutStatusResponse = () => buildCodecForObject().property("amount
var codecForMonitorResponse = () => buildCodecForUnion().discriminateOn("type").alternative("no-conversions", codecForMonitorNoConversion()).alternative("with-conversions", codecForMonitorWithCashout()).build("TalerWireGatewayApi.IncomingBankTransaction");
var codecForMonitorNoConversion = () => buildCodecForObject().property("type", codecForConstString("no-conversions")).property("talerInCount", codecForNumber()).property("talerInVolume", codecForAmountString()).property("talerOutCount", codecForNumber()).property("talerOutVolume", codecForAmountString()).build("TalerCorebankApi.MonitorJustPayouts");
var codecForMonitorWithCashout = () => buildCodecForObject().property("type", codecForConstString("with-conversions")).property("cashinCount", codecForNumber()).property("cashinFiatVolume", codecForAmountString()).property("cashinRegionalVolume", codecForAmountString()).property("cashoutCount", codecForNumber()).property("cashoutFiatVolume", codecForAmountString()).property("cashoutRegionalVolume", codecForAmountString()).property("talerInCount", codecForNumber()).property("talerInVolume", codecForAmountString()).property("talerOutCount", codecForNumber()).property("talerOutVolume", codecForAmountString()).build("TalerCorebankApi.MonitorWithCashout");
-var codecForBankWithdrawalOperationStatus = () => buildCodecForObject().property("status", codecForEither(codecForConstString("pending"), codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"))).property("amount", codecForAmountString()).property("sender_wire", codecOptional(codecForPaytoString())).property("suggested_exchange", codecOptional(codecForString())).property("confirm_transfer_url", codecOptional(codecForURL())).property("wire_types", codecForList(codecForString())).property("selected_reserve_pub", codecOptional(codecForString())).property("selected_exchange_account", codecOptional(codecForString())).build("TalerBankIntegrationApi.BankWithdrawalOperationStatus");
-var codecForBankWithdrawalOperationPostResponse = () => buildCodecForObject().property("status", codecForEither(codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"))).property("confirm_transfer_url", codecOptional(codecForURL())).build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse");
-var codecForMerchantIncomingHistory = () => buildCodecForObject().property("credit_account", codecForPaytoString()).property("incoming_transactions", codecForList(codecForMerchantIncomingBankTransaction())).build("TalerRevenueApi.MerchantIncomingHistory");
-var codecForMerchantIncomingBankTransaction = () => buildCodecForObject().property("row_id", codecForNumber()).property("date", codecForTimestamp).property("amount", codecForAmountString()).property("debit_account", codecForPaytoString()).property("exchange_url", codecForURL()).property("wtid", codecForString()).build("TalerRevenueApi.MerchantIncomingBankTransaction");
-var codecForTransferResponse = () => buildCodecForObject().property("row_id", codecForNumber()).property("timestamp", codecForTimestamp).build("TalerWireGatewayApi.TransferResponse");
-var codecForIncomingHistory = () => buildCodecForObject().property("credit_account", codecForPaytoString()).property("incoming_transactions", codecForList(codecForIncomingBankTransaction())).build("TalerWireGatewayApi.IncomingHistory");
-var codecForIncomingBankTransaction = () => buildCodecForUnion().discriminateOn("type").alternative("RESERVE", codecForIncomingReserveTransaction()).alternative("WAD", codecForIncomingWadTransaction()).build("TalerWireGatewayApi.IncomingBankTransaction");
-var codecForIncomingReserveTransaction = () => buildCodecForObject().property("amount", codecForAmountString()).property("date", codecForTimestamp).property("debit_account", codecForPaytoString()).property("reserve_pub", codecForString()).property("row_id", codecForNumber()).property("type", codecForConstString("RESERVE")).build("TalerWireGatewayApi.IncomingReserveTransaction");
-var codecForIncomingWadTransaction = () => buildCodecForObject().property("amount", codecForAmountString()).property("credit_account", codecForPaytoString()).property("date", codecForTimestamp).property("debit_account", codecForPaytoString()).property("origin_exchange_url", codecForURL()).property("row_id", codecForNumber()).property("type", codecForConstString("WAD")).property("wad_id", codecForString()).build("TalerWireGatewayApi.IncomingWadTransaction");
-var codecForOutgoingHistory = () => buildCodecForObject().property("debit_account", codecForPaytoString()).property("outgoing_transactions", codecForList(codecForOutgoingBankTransaction())).build("TalerWireGatewayApi.OutgoingHistory");
-var codecForOutgoingBankTransaction = () => buildCodecForObject().property("amount", codecForAmountString()).property("credit_account", codecForPaytoString()).property("date", codecForTimestamp).property("exchange_base_url", codecForURL()).property("row_id", codecForNumber()).property("wtid", codecForString()).build("TalerWireGatewayApi.OutgoingBankTransaction");
-var codecForAddIncomingResponse = () => buildCodecForObject().property("row_id", codecForNumber()).property("timestamp", codecForTimestamp).build("TalerWireGatewayApi.AddIncomingResponse");
var codecForChallenge = () => buildCodecForObject().property("challenge_id", codecForNumber()).build("TalerCorebankApi.Challenge");
var codecForTanTransmission = () => buildCodecForObject().property("tan_channel", codecForEither(codecForConstString(TalerCorebankApi.TanChannel.SMS), codecForConstString(TalerCorebankApi.TanChannel.EMAIL))).property("tan_info", codecForString()).build("TalerCorebankApi.TanTransmission");
var codecForConversionInfo = () => buildCodecForObject().property("cashin_fee", codecForAmountString()).property("cashin_min_amount", codecForAmountString()).property("cashin_ratio", codecForDecimalNumber()).property("cashin_rounding_mode", codecForEither(codecForConstString("zero"), codecForConstString("up"), codecForConstString("nearest"))).property("cashin_tiny_amount", codecForAmountString()).property("cashout_fee", codecForAmountString()).property("cashout_min_amount", codecForAmountString()).property("cashout_ratio", codecForDecimalNumber()).property("cashout_rounding_mode", codecForEither(codecForConstString("zero"), codecForConstString("up"), codecForConstString("nearest"))).property("cashout_tiny_amount", codecForAmountString()).build("ConversionBankConfig.ConversionInfo");
var codecForConversionBankConfig = () => buildCodecForObject().property("name", codecForConstString("taler-conversion-info")).property("version", codecForString()).property("regional_currency", codecForString()).property("regional_currency_specification", codecForCurrencySpecificiation()).property("fiat_currency", codecForString()).property("fiat_currency_specification", codecForCurrencySpecificiation()).property("conversion_rate", codecForConversionInfo()).build("ConversionBankConfig.IntegrationConfig");
-var codecForURL = codecForString;
var codecForDecimalNumber = codecForString;
var TalerCorebankApi;
-(function(TalerCorebankApi8) {
+(function(TalerCorebankApi7) {
let MonitorTimeframeParam;
(function(MonitorTimeframeParam2) {
MonitorTimeframeParam2[MonitorTimeframeParam2["hour"] = 0] = "hour";
@@ -11980,12 +11970,12 @@ var TalerCorebankApi;
MonitorTimeframeParam2[MonitorTimeframeParam2["month"] = 2] = "month";
MonitorTimeframeParam2[MonitorTimeframeParam2["year"] = 3] = "year";
MonitorTimeframeParam2[MonitorTimeframeParam2["decade"] = 4] = "decade";
- })(MonitorTimeframeParam = TalerCorebankApi8.MonitorTimeframeParam || (TalerCorebankApi8.MonitorTimeframeParam = {}));
- let TanChannel2;
- (function(TanChannel3) {
- TanChannel3["SMS"] = "sms";
- TanChannel3["EMAIL"] = "email";
- })(TanChannel2 = TalerCorebankApi8.TanChannel || (TalerCorebankApi8.TanChannel = {}));
+ })(MonitorTimeframeParam = TalerCorebankApi7.MonitorTimeframeParam || (TalerCorebankApi7.MonitorTimeframeParam = {}));
+ let TanChannel3;
+ (function(TanChannel4) {
+ TanChannel4["SMS"] = "sms";
+ TanChannel4["EMAIL"] = "email";
+ })(TanChannel3 = TalerCorebankApi7.TanChannel || (TalerCorebankApi7.TanChannel = {}));
})(TalerCorebankApi || (TalerCorebankApi = {}));
var TalerExchangeApi;
(function(TalerExchangeApi2) {
@@ -11996,71 +11986,79 @@ var TalerExchangeApi;
AmlState2[AmlState2["frozen"] = 2] = "frozen";
})(AmlState = TalerExchangeApi2.AmlState || (TalerExchangeApi2.AmlState = {}));
})(TalerExchangeApi || (TalerExchangeApi = {}));
+var TalerMerchantApi;
+(function(TalerMerchantApi2) {
+ let TokenFamilyKind;
+ (function(TokenFamilyKind2) {
+ TokenFamilyKind2["Discount"] = "discount";
+ TokenFamilyKind2["Subscription"] = "subscription";
+ })(TokenFamilyKind = TalerMerchantApi2.TokenFamilyKind || (TalerMerchantApi2.TokenFamilyKind = {}));
+})(TalerMerchantApi || (TalerMerchantApi = {}));
// ../taler-util/lib/http-status-codes.js
var HttpStatusCode;
-(function(HttpStatusCode3) {
- HttpStatusCode3[HttpStatusCode3["Continue"] = 100] = "Continue";
- HttpStatusCode3[HttpStatusCode3["SwitchingProtocols"] = 101] = "SwitchingProtocols";
- HttpStatusCode3[HttpStatusCode3["Processing"] = 102] = "Processing";
- HttpStatusCode3[HttpStatusCode3["Ok"] = 200] = "Ok";
- HttpStatusCode3[HttpStatusCode3["Created"] = 201] = "Created";
- HttpStatusCode3[HttpStatusCode3["Accepted"] = 202] = "Accepted";
- HttpStatusCode3[HttpStatusCode3["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
- HttpStatusCode3[HttpStatusCode3["NoContent"] = 204] = "NoContent";
- HttpStatusCode3[HttpStatusCode3["ResetContent"] = 205] = "ResetContent";
- HttpStatusCode3[HttpStatusCode3["PartialContent"] = 206] = "PartialContent";
- HttpStatusCode3[HttpStatusCode3["MultiStatus"] = 207] = "MultiStatus";
- HttpStatusCode3[HttpStatusCode3["AlreadyReported"] = 208] = "AlreadyReported";
- HttpStatusCode3[HttpStatusCode3["ImUsed"] = 226] = "ImUsed";
- HttpStatusCode3[HttpStatusCode3["MultipleChoices"] = 300] = "MultipleChoices";
- HttpStatusCode3[HttpStatusCode3["MovedPermanently"] = 301] = "MovedPermanently";
- HttpStatusCode3[HttpStatusCode3["Found"] = 302] = "Found";
- HttpStatusCode3[HttpStatusCode3["SeeOther"] = 303] = "SeeOther";
- HttpStatusCode3[HttpStatusCode3["NotModified"] = 304] = "NotModified";
- HttpStatusCode3[HttpStatusCode3["UseProxy"] = 305] = "UseProxy";
- HttpStatusCode3[HttpStatusCode3["SwitchProxy"] = 306] = "SwitchProxy";
- HttpStatusCode3[HttpStatusCode3["TemporaryRedirect"] = 307] = "TemporaryRedirect";
- HttpStatusCode3[HttpStatusCode3["PermanentRedirect"] = 308] = "PermanentRedirect";
- HttpStatusCode3[HttpStatusCode3["BadRequest"] = 400] = "BadRequest";
- HttpStatusCode3[HttpStatusCode3["Unauthorized"] = 401] = "Unauthorized";
- HttpStatusCode3[HttpStatusCode3["PaymentRequired"] = 402] = "PaymentRequired";
- HttpStatusCode3[HttpStatusCode3["Forbidden"] = 403] = "Forbidden";
- HttpStatusCode3[HttpStatusCode3["NotFound"] = 404] = "NotFound";
- HttpStatusCode3[HttpStatusCode3["MethodNotAllowed"] = 405] = "MethodNotAllowed";
- HttpStatusCode3[HttpStatusCode3["NotAcceptable"] = 406] = "NotAcceptable";
- HttpStatusCode3[HttpStatusCode3["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
- HttpStatusCode3[HttpStatusCode3["RequestTimeout"] = 408] = "RequestTimeout";
- HttpStatusCode3[HttpStatusCode3["Conflict"] = 409] = "Conflict";
- HttpStatusCode3[HttpStatusCode3["Gone"] = 410] = "Gone";
- HttpStatusCode3[HttpStatusCode3["LengthRequired"] = 411] = "LengthRequired";
- HttpStatusCode3[HttpStatusCode3["PreconditionFailed"] = 412] = "PreconditionFailed";
- HttpStatusCode3[HttpStatusCode3["PayloadTooLarge"] = 413] = "PayloadTooLarge";
- HttpStatusCode3[HttpStatusCode3["UriTooLong"] = 414] = "UriTooLong";
- HttpStatusCode3[HttpStatusCode3["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
- HttpStatusCode3[HttpStatusCode3["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
- HttpStatusCode3[HttpStatusCode3["ExpectationFailed"] = 417] = "ExpectationFailed";
- HttpStatusCode3[HttpStatusCode3["IAmATeapot"] = 418] = "IAmATeapot";
- HttpStatusCode3[HttpStatusCode3["MisdirectedRequest"] = 421] = "MisdirectedRequest";
- HttpStatusCode3[HttpStatusCode3["UnprocessableEntity"] = 422] = "UnprocessableEntity";
- HttpStatusCode3[HttpStatusCode3["Locked"] = 423] = "Locked";
- HttpStatusCode3[HttpStatusCode3["FailedDependency"] = 424] = "FailedDependency";
- HttpStatusCode3[HttpStatusCode3["UpgradeRequired"] = 426] = "UpgradeRequired";
- HttpStatusCode3[HttpStatusCode3["PreconditionRequired"] = 428] = "PreconditionRequired";
- HttpStatusCode3[HttpStatusCode3["TooManyRequests"] = 429] = "TooManyRequests";
- HttpStatusCode3[HttpStatusCode3["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
- HttpStatusCode3[HttpStatusCode3["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
- HttpStatusCode3[HttpStatusCode3["InternalServerError"] = 500] = "InternalServerError";
- HttpStatusCode3[HttpStatusCode3["NotImplemented"] = 501] = "NotImplemented";
- HttpStatusCode3[HttpStatusCode3["BadGateway"] = 502] = "BadGateway";
- HttpStatusCode3[HttpStatusCode3["ServiceUnavailable"] = 503] = "ServiceUnavailable";
- HttpStatusCode3[HttpStatusCode3["GatewayTimeout"] = 504] = "GatewayTimeout";
- HttpStatusCode3[HttpStatusCode3["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
- HttpStatusCode3[HttpStatusCode3["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
- HttpStatusCode3[HttpStatusCode3["InsufficientStorage"] = 507] = "InsufficientStorage";
- HttpStatusCode3[HttpStatusCode3["LoopDetected"] = 508] = "LoopDetected";
- HttpStatusCode3[HttpStatusCode3["NotExtended"] = 510] = "NotExtended";
- HttpStatusCode3[HttpStatusCode3["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
+(function(HttpStatusCode2) {
+ HttpStatusCode2[HttpStatusCode2["Continue"] = 100] = "Continue";
+ HttpStatusCode2[HttpStatusCode2["SwitchingProtocols"] = 101] = "SwitchingProtocols";
+ HttpStatusCode2[HttpStatusCode2["Processing"] = 102] = "Processing";
+ HttpStatusCode2[HttpStatusCode2["Ok"] = 200] = "Ok";
+ HttpStatusCode2[HttpStatusCode2["Created"] = 201] = "Created";
+ HttpStatusCode2[HttpStatusCode2["Accepted"] = 202] = "Accepted";
+ HttpStatusCode2[HttpStatusCode2["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
+ HttpStatusCode2[HttpStatusCode2["NoContent"] = 204] = "NoContent";
+ HttpStatusCode2[HttpStatusCode2["ResetContent"] = 205] = "ResetContent";
+ HttpStatusCode2[HttpStatusCode2["PartialContent"] = 206] = "PartialContent";
+ HttpStatusCode2[HttpStatusCode2["MultiStatus"] = 207] = "MultiStatus";
+ HttpStatusCode2[HttpStatusCode2["AlreadyReported"] = 208] = "AlreadyReported";
+ HttpStatusCode2[HttpStatusCode2["ImUsed"] = 226] = "ImUsed";
+ HttpStatusCode2[HttpStatusCode2["MultipleChoices"] = 300] = "MultipleChoices";
+ HttpStatusCode2[HttpStatusCode2["MovedPermanently"] = 301] = "MovedPermanently";
+ HttpStatusCode2[HttpStatusCode2["Found"] = 302] = "Found";
+ HttpStatusCode2[HttpStatusCode2["SeeOther"] = 303] = "SeeOther";
+ HttpStatusCode2[HttpStatusCode2["NotModified"] = 304] = "NotModified";
+ HttpStatusCode2[HttpStatusCode2["UseProxy"] = 305] = "UseProxy";
+ HttpStatusCode2[HttpStatusCode2["SwitchProxy"] = 306] = "SwitchProxy";
+ HttpStatusCode2[HttpStatusCode2["TemporaryRedirect"] = 307] = "TemporaryRedirect";
+ HttpStatusCode2[HttpStatusCode2["PermanentRedirect"] = 308] = "PermanentRedirect";
+ HttpStatusCode2[HttpStatusCode2["BadRequest"] = 400] = "BadRequest";
+ HttpStatusCode2[HttpStatusCode2["Unauthorized"] = 401] = "Unauthorized";
+ HttpStatusCode2[HttpStatusCode2["PaymentRequired"] = 402] = "PaymentRequired";
+ HttpStatusCode2[HttpStatusCode2["Forbidden"] = 403] = "Forbidden";
+ HttpStatusCode2[HttpStatusCode2["NotFound"] = 404] = "NotFound";
+ HttpStatusCode2[HttpStatusCode2["MethodNotAllowed"] = 405] = "MethodNotAllowed";
+ HttpStatusCode2[HttpStatusCode2["NotAcceptable"] = 406] = "NotAcceptable";
+ HttpStatusCode2[HttpStatusCode2["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
+ HttpStatusCode2[HttpStatusCode2["RequestTimeout"] = 408] = "RequestTimeout";
+ HttpStatusCode2[HttpStatusCode2["Conflict"] = 409] = "Conflict";
+ HttpStatusCode2[HttpStatusCode2["Gone"] = 410] = "Gone";
+ HttpStatusCode2[HttpStatusCode2["LengthRequired"] = 411] = "LengthRequired";
+ HttpStatusCode2[HttpStatusCode2["PreconditionFailed"] = 412] = "PreconditionFailed";
+ HttpStatusCode2[HttpStatusCode2["PayloadTooLarge"] = 413] = "PayloadTooLarge";
+ HttpStatusCode2[HttpStatusCode2["UriTooLong"] = 414] = "UriTooLong";
+ HttpStatusCode2[HttpStatusCode2["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
+ HttpStatusCode2[HttpStatusCode2["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
+ HttpStatusCode2[HttpStatusCode2["ExpectationFailed"] = 417] = "ExpectationFailed";
+ HttpStatusCode2[HttpStatusCode2["IAmATeapot"] = 418] = "IAmATeapot";
+ HttpStatusCode2[HttpStatusCode2["MisdirectedRequest"] = 421] = "MisdirectedRequest";
+ HttpStatusCode2[HttpStatusCode2["UnprocessableEntity"] = 422] = "UnprocessableEntity";
+ HttpStatusCode2[HttpStatusCode2["Locked"] = 423] = "Locked";
+ HttpStatusCode2[HttpStatusCode2["FailedDependency"] = 424] = "FailedDependency";
+ HttpStatusCode2[HttpStatusCode2["UpgradeRequired"] = 426] = "UpgradeRequired";
+ HttpStatusCode2[HttpStatusCode2["PreconditionRequired"] = 428] = "PreconditionRequired";
+ HttpStatusCode2[HttpStatusCode2["TooManyRequests"] = 429] = "TooManyRequests";
+ HttpStatusCode2[HttpStatusCode2["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
+ HttpStatusCode2[HttpStatusCode2["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
+ HttpStatusCode2[HttpStatusCode2["InternalServerError"] = 500] = "InternalServerError";
+ HttpStatusCode2[HttpStatusCode2["NotImplemented"] = 501] = "NotImplemented";
+ HttpStatusCode2[HttpStatusCode2["BadGateway"] = 502] = "BadGateway";
+ HttpStatusCode2[HttpStatusCode2["ServiceUnavailable"] = 503] = "ServiceUnavailable";
+ HttpStatusCode2[HttpStatusCode2["GatewayTimeout"] = 504] = "GatewayTimeout";
+ HttpStatusCode2[HttpStatusCode2["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
+ HttpStatusCode2[HttpStatusCode2["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
+ HttpStatusCode2[HttpStatusCode2["InsufficientStorage"] = 507] = "InsufficientStorage";
+ HttpStatusCode2[HttpStatusCode2["LoopDetected"] = 508] = "LoopDetected";
+ HttpStatusCode2[HttpStatusCode2["NotExtended"] = 510] = "NotExtended";
+ HttpStatusCode2[HttpStatusCode2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
})(HttpStatusCode || (HttpStatusCode = {}));
// ../taler-util/lib/http-impl.missing.js
@@ -12252,27 +12250,27 @@ var LibtoolVersion;
})(LibtoolVersion || (LibtoolVersion = {}));
// ../taler-util/lib/operation.js
-async function opSuccess(resp, codec) {
+async function opSuccessFromHttp(resp, codec) {
const body = await readSuccessResponseJsonOrThrow(resp, codec);
- return { type: "ok", body, httpResp: resp };
+ return { type: "ok", body };
}
-function opFixedSuccess(resp, body) {
- return { type: "ok", body, httpResp: resp };
+function opFixedSuccess(body) {
+ return { type: "ok", body };
}
function opEmptySuccess(resp) {
- return { type: "ok", body: void 0, httpResp: resp };
+ return { type: "ok", body: void 0 };
}
async function opKnownAlternativeFailure(resp, s5, codec) {
const body = await readSuccessResponseJsonOrThrow(resp, codec);
- return { type: "fail", case: s5, body, httpResp: resp };
+ return { type: "fail", case: s5, body };
}
async function opKnownHttpFailure(s5, resp) {
const detail = await readTalerErrorResponse(resp);
- return { type: "fail", case: s5, detail, httpResp: resp };
+ return { type: "fail", case: s5, detail };
}
async function opKnownTalerFailure(s5, resp) {
const detail = await readTalerErrorResponse(resp);
- return { type: "fail", case: s5, detail, httpResp: resp };
+ return { type: "fail", case: s5, detail };
}
function opUnknownFailure(resp, text) {
throw TalerError.fromDetail(TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, {
@@ -12938,13 +12936,21 @@ function addLongPollingParam(url, param) {
url.searchParams.set("long_poll_ms", String(param.timeoutMs));
}
}
+var nullEvictor = {
+ notifySuccess: () => Promise.resolve()
+};
// ../taler-util/lib/http-client/bank-conversion.js
+var TalerBankConversionCacheEviction;
+(function(TalerBankConversionCacheEviction2) {
+ TalerBankConversionCacheEviction2[TalerBankConversionCacheEviction2["UPDATE_RATE"] = 0] = "UPDATE_RATE";
+})(TalerBankConversionCacheEviction || (TalerBankConversionCacheEviction = {}));
var TalerBankConversionHttpClient = class {
- constructor(baseUrl, httpClient) {
+ constructor(baseUrl, httpClient, cacheEvictor) {
this.baseUrl = baseUrl;
this.PROTOCOL_VERSION = "0:0:0";
this.httpLib = httpClient ?? createPlatformHttpLib();
+ this.cacheEvictor = cacheEvictor ?? nullEvictor;
}
isCompatible(version) {
const compare2 = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
@@ -12961,7 +12967,7 @@ var TalerBankConversionHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForConversionBankConfig());
+ return opSuccessFromHttp(resp, codecForConversionBankConfig());
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
@@ -12985,7 +12991,7 @@ var TalerBankConversionHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCashinConversionResponse());
+ return opSuccessFromHttp(resp, codecForCashinConversionResponse());
case HttpStatusCode.BadRequest: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
@@ -13025,7 +13031,7 @@ var TalerBankConversionHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCashoutConversionResponse());
+ return opSuccessFromHttp(resp, codecForCashoutConversionResponse());
case HttpStatusCode.BadRequest: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
@@ -13062,8 +13068,10 @@ var TalerBankConversionHttpClient = class {
body
});
switch (resp.status) {
- case HttpStatusCode.NoContent:
+ case HttpStatusCode.NoContent: {
+ this.cacheEvictor.notifySuccess(TalerBankConversionCacheEviction.UPDATE_RATE);
return opEmptySuccess(resp);
+ }
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotImplemented:
@@ -13102,7 +13110,7 @@ var TalerAuthenticationHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForTokenSuccessResponse());
+ return opSuccessFromHttp(resp, codecForTokenSuccessResponse());
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -13130,322 +13138,25 @@ var TalerAuthenticationHttpClient = class {
}
};
-// ../taler-util/lib/http-client/bank-integration.js
-var TalerBankIntegrationHttpClient = class {
- constructor(baseUrl, httpClient) {
- this.baseUrl = baseUrl;
- this.PROTOCOL_VERSION = "2:0:2";
- this.httpLib = httpClient ?? createPlatformHttpLib();
- }
- isCompatible(version) {
- const compare2 = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
- return compare2?.compatible ?? false;
- }
- /**
- * https://docs.taler.net/core/api-bank-integration.html#get--config
- *
- */
- async getConfig() {
- const url = new URL(`config`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET"
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForIntegrationBankConfig());
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
- /**
- * https://docs.taler.net/core/api-bank-integration.html#get--withdrawal-operation-$WITHDRAWAL_ID
- *
- */
- async getWithdrawalOperationById(woid, params) {
- const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl);
- addLongPollingParam(url, params);
- if (params) {
- url.searchParams.set("old_state", !params.old_state ? "pending" : params.old_state);
- }
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET"
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForBankWithdrawalOperationStatus());
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
- /**
- * https://docs.taler.net/core/api-bank-integration.html#post-$BANK_API_BASE_URL-withdrawal-operation-$wopid
- *
- */
- async completeWithdrawalOperationById(woid, body) {
- const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForBankWithdrawalOperationPostResponse());
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Conflict: {
- const body2 = await resp.json();
- const details = codecForTalerErrorDetail().decode(body2);
- switch (details.code) {
- case TalerErrorCode.BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT:
- return opKnownTalerFailure(details.code, resp);
- case TalerErrorCode.BANK_DUPLICATE_RESERVE_PUB_SUBJECT:
- return opKnownTalerFailure(details.code, resp);
- case TalerErrorCode.BANK_UNKNOWN_ACCOUNT:
- return opKnownTalerFailure(details.code, resp);
- case TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE:
- return opKnownTalerFailure(details.code, resp);
- default:
- return opUnknownFailure(resp, body2);
- }
- }
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
- /**
- * https://docs.taler.net/core/api-bank-integration.html#post-$BANK_API_BASE_URL-withdrawal-operation-$wopid
- *
- */
- async abortWithdrawalOperationById(woid) {
- const url = new URL(`withdrawal-operation/${woid}/abort`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST"
- });
- switch (resp.status) {
- case HttpStatusCode.NoContent:
- return opEmptySuccess(resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
-};
-
-// ../taler-util/lib/http-client/bank-revenue.js
-var TalerRevenueHttpClient = class {
- constructor(baseUrl, username, httpClient) {
- this.baseUrl = baseUrl;
- this.username = username;
- this.httpLib = httpClient ?? createPlatformHttpLib();
- }
- // public readonly PROTOCOL_VERSION = "4:0:0";
- // isCompatible(version: string): boolean {
- // const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
- // return compare?.compatible ?? false
- // }
- // /**
- // * https://docs.taler.net/core/api-corebank.html#config
- // *
- // */
- // async getConfig() {
- // const url = new URL(`config`, this.baseUrl);
- // const resp = await this.httpLib.fetch(url.href, {
- // method: "GET"
- // });
- // switch (resp.status) {
- // case HttpStatusCode.Ok: return opSuccess(resp, codecForCoreBankConfig())
- // default: return opUnknownFailure(resp, await resp.text())
- // }
- // }
- /**
- * https://docs.taler.net/core/api-bank-revenue.html#get--history
- *
- * @returns
- */
- async getHistory(auth, params) {
- const url = new URL(`history`, this.baseUrl);
- addPaginationParams(url, params);
- addLongPollingParam(url, params);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- headers: {
- Authorization: makeBasicAuthHeader(this.username, auth)
- }
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForMerchantIncomingHistory());
- case HttpStatusCode.BadRequest:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
-};
-
-// ../taler-util/lib/http-client/bank-wire.js
-var TalerWireGatewayHttpClient = class {
- constructor(baseUrl, username, httpClient) {
- this.baseUrl = baseUrl;
- this.username = username;
- this.httpLib = httpClient ?? createPlatformHttpLib();
- }
- // public readonly PROTOCOL_VERSION = "4:0:0";
- // isCompatible(version: string): boolean {
- // const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
- // return compare?.compatible ?? false
- // }
- // /**
- // * https://docs.taler.net/core/api-corebank.html#config
- // *
- // */
- // async getConfig() {
- // const url = new URL(`config`, this.baseUrl);
- // const resp = await this.httpLib.fetch(url.href, {
- // method: "GET"
- // });
- // switch (resp.status) {
- // case HttpStatusCode.Ok: return opSuccess(resp, codecForCoreBankConfig())
- // default: return opUnknownFailure(resp, await resp.text())
- // }
- // }
- /**
- * https://docs.taler.net/core/api-bank-wire.html#post--transfer
- *
- */
- async transfer(auth, body) {
- const url = new URL(`transfer`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- headers: {
- Authorization: makeBasicAuthHeader(this.username, auth)
- },
- body
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForTransferResponse());
- case HttpStatusCode.BadRequest:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
- /**
- * https://docs.taler.net/core/api-bank-wire.html#get--history-incoming
- *
- */
- async getHistoryIncoming(auth, params) {
- const url = new URL(`history/incoming`, this.baseUrl);
- addPaginationParams(url, params);
- addLongPollingParam(url, params);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- headers: {
- Authorization: makeBasicAuthHeader(this.username, auth)
- }
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForIncomingHistory());
- case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, {
- incoming_transactions: [],
- credit_account: void 0
- });
- case HttpStatusCode.BadRequest:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
- /**
- * https://docs.taler.net/core/api-bank-wire.html#get--history-outgoing
- *
- */
- async getHistoryOutgoing(auth, params) {
- const url = new URL(`history/outgoing`, this.baseUrl);
- addPaginationParams(url, params);
- addLongPollingParam(url, params);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- headers: {
- Authorization: makeBasicAuthHeader(this.username, auth)
- }
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForOutgoingHistory());
- case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, {
- outgoing_transactions: [],
- debit_account: void 0
- });
- case HttpStatusCode.BadRequest:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
- /**
- * https://docs.taler.net/core/api-bank-wire.html#post--admin-add-incoming
- *
- */
- async addIncoming(auth, body) {
- const url = new URL(`admin/add-incoming`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- headers: {
- Authorization: makeBasicAuthHeader(this.username, auth)
- },
- body
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForAddIncomingResponse());
- case HttpStatusCode.BadRequest:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await resp.text());
- }
- }
-};
-
// ../taler-util/lib/http-client/bank-core.js
+var TalerCoreBankCacheEviction;
+(function(TalerCoreBankCacheEviction2) {
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["DELETE_ACCOUNT"] = 0] = "DELETE_ACCOUNT";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_ACCOUNT"] = 1] = "CREATE_ACCOUNT";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["UPDATE_ACCOUNT"] = 2] = "UPDATE_ACCOUNT";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["UPDATE_PASSWORD"] = 3] = "UPDATE_PASSWORD";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_TRANSACTION"] = 4] = "CREATE_TRANSACTION";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CONFIRM_WITHDRAWAL"] = 5] = "CONFIRM_WITHDRAWAL";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["ABORT_WITHDRAWAL"] = 6] = "ABORT_WITHDRAWAL";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_WITHDRAWAL"] = 7] = "CREATE_WITHDRAWAL";
+ TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_CASHOUT"] = 8] = "CREATE_CASHOUT";
+})(TalerCoreBankCacheEviction || (TalerCoreBankCacheEviction = {}));
var TalerCoreBankHttpClient = class {
- constructor(baseUrl, httpClient) {
+ constructor(baseUrl, httpClient, cacheEvictor) {
this.baseUrl = baseUrl;
this.PROTOCOL_VERSION = "4:0:0";
this.httpLib = httpClient ?? createPlatformHttpLib();
+ this.cacheEvictor = cacheEvictor ?? nullEvictor;
}
isCompatible(version) {
const compare2 = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
@@ -13462,7 +13173,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCoreBankConfig());
+ return opSuccessFromHttp(resp, codecForCoreBankConfig());
default:
return opUnknownFailure(resp, await resp.text());
}
@@ -13484,8 +13195,10 @@ var TalerCoreBankHttpClient = class {
}
});
switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccess(resp, codecForRegisterAccountResponse());
+ case HttpStatusCode.Ok: {
+ await this.cacheEvictor.notifySuccess(TalerCoreBankCacheEviction.CREATE_ACCOUNT);
+ return opSuccessFromHttp(resp, codecForRegisterAccountResponse());
+ }
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
@@ -13655,11 +13368,11 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForPublicAccountsResponse());
+ return opSuccessFromHttp(resp, codecForPublicAccountsResponse());
case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, { public_accounts: [] });
+ return opFixedSuccess({ public_accounts: [] });
case HttpStatusCode.NotFound:
- return opFixedSuccess(resp, { public_accounts: [] });
+ return opFixedSuccess({ public_accounts: [] });
default:
return opUnknownFailure(resp, await resp.text());
}
@@ -13682,9 +13395,9 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForListBankAccountsResponse());
+ return opSuccessFromHttp(resp, codecForListBankAccountsResponse());
case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, { accounts: [] });
+ return opFixedSuccess({ accounts: [] });
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
default:
@@ -13705,7 +13418,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForAccountData());
+ return opSuccessFromHttp(resp, codecForAccountData());
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -13733,9 +13446,9 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForBankAccountTransactionsResponse());
+ return opSuccessFromHttp(resp, codecForBankAccountTransactionsResponse());
case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, { transactions: [] });
+ return opFixedSuccess({ transactions: [] });
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -13758,7 +13471,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForBankAccountTransactionInfo());
+ return opSuccessFromHttp(resp, codecForBankAccountTransactionInfo());
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
@@ -13783,7 +13496,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCreateTransactionResponse());
+ return opSuccessFromHttp(resp, codecForCreateTransactionResponse());
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(resp, resp.status, codecForChallenge());
case HttpStatusCode.BadRequest:
@@ -13796,6 +13509,8 @@ var TalerCoreBankHttpClient = class {
const body2 = await resp.json();
const details = codecForTalerErrorDetail().decode(body2);
switch (details.code) {
+ case TalerErrorCode.BANK_ADMIN_CREDITOR:
+ return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_SAME_ACCOUNT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_UNKNOWN_CREDITOR:
@@ -13828,7 +13543,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForBankAccountCreateWithdrawalResponse());
+ return opSuccessFromHttp(resp, codecForBankAccountCreateWithdrawalResponse());
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict:
@@ -13919,7 +13634,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForWithdrawalPublicInfo());
+ return opSuccessFromHttp(resp, codecForWithdrawalPublicInfo());
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -13947,7 +13662,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCashoutPending());
+ return opSuccessFromHttp(resp, codecForCashoutPending());
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(resp, resp.status, codecForChallenge());
case HttpStatusCode.NotFound:
@@ -13998,7 +13713,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCashoutStatusResponse());
+ return opSuccessFromHttp(resp, codecForCashoutStatusResponse());
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotImplemented:
@@ -14022,9 +13737,9 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForCashouts());
+ return opSuccessFromHttp(resp, codecForCashouts());
case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, { cashouts: [] });
+ return opFixedSuccess({ cashouts: [] });
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
@@ -14046,9 +13761,9 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForGlobalCashouts());
+ return opSuccessFromHttp(resp, codecForGlobalCashouts());
case HttpStatusCode.NoContent:
- return opFixedSuccess(resp, { cashouts: [] });
+ return opFixedSuccess({ cashouts: [] });
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
@@ -14072,7 +13787,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForTanTransmission());
+ return opSuccessFromHttp(resp, codecForTanTransmission());
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -14152,7 +13867,7 @@ var TalerCoreBankHttpClient = class {
});
switch (resp.status) {
case HttpStatusCode.Ok:
- return opSuccess(resp, codecForMonitorResponse());
+ return opSuccessFromHttp(resp, codecForMonitorResponse());
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
@@ -14169,43 +13884,48 @@ var TalerCoreBankHttpClient = class {
*
*/
getIntegrationAPI() {
- const url = new URL(`taler-integration/`, this.baseUrl);
- return new TalerBankIntegrationHttpClient(url.href, this.httpLib);
+ return new URL(`taler-integration/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
*
*/
getWireGatewayAPI(username) {
- const url = new URL(`accounts/${username}/taler-wire-gateway/`, this.baseUrl);
- return new TalerWireGatewayHttpClient(url.href, username, this.httpLib);
+ return new URL(`accounts/${username}/taler-wire-gateway/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
*
*/
getRevenueAPI(username) {
- const url = new URL(`accounts/${username}/taler-revenue/`, this.baseUrl);
- return new TalerRevenueHttpClient(url.href, username, this.httpLib);
+ return new URL(`accounts/${username}/taler-revenue/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
*
*/
getAuthenticationAPI(username) {
- const url = new URL(`accounts/${username}/`, this.baseUrl);
- return new TalerAuthenticationHttpClient(url.href, username, this.httpLib);
+ return new URL(`accounts/${username}/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
*
*/
getConversionInfoAPI() {
- const url = new URL(`conversion-info/`, this.baseUrl);
- return new TalerBankConversionHttpClient(url.href, this.httpLib);
+ return new URL(`conversion-info/`, this.baseUrl);
}
};
+// ../taler-util/lib/http-client/merchant.js
+var TalerMerchantInstanceCacheEviction;
+(function(TalerMerchantInstanceCacheEviction2) {
+ TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_ORDER"] = 0] = "CREATE_ORDER";
+})(TalerMerchantInstanceCacheEviction || (TalerMerchantInstanceCacheEviction = {}));
+var TalerMerchantManagementCacheEviction;
+(function(TalerMerchantManagementCacheEviction2) {
+ TalerMerchantManagementCacheEviction2[TalerMerchantManagementCacheEviction2["CREATE_INSTANCE"] = 0] = "CREATE_INSTANCE";
+})(TalerMerchantManagementCacheEviction || (TalerMerchantManagementCacheEviction = {}));
+
// ../taler-util/lib/i18n.js
var jedLib = __toESM(require_jed(), 1);
var logger9 = new Logger("i18n/index.ts");
@@ -14330,6 +14050,61 @@ var ObservabilityEventType;
ObservabilityEventType2["CryptoFinishError"] = "crypto-finish-error";
})(ObservabilityEventType || (ObservabilityEventType = {}));
+// ../taler-util/lib/observability.js
+var seqId = 1e3;
+var ObservableHttpClientLibrary = class {
+ constructor(impl, oc) {
+ this.impl = impl;
+ this.oc = oc;
+ this.cancelatorById = /* @__PURE__ */ new Map();
+ }
+ cancelRequest(id) {
+ const cancelator = this.cancelatorById.get(id);
+ if (!cancelator)
+ return;
+ cancelator.cancel();
+ }
+ async fetch(url, opt) {
+ const id = `req-${seqId}`;
+ seqId = seqId + 1;
+ const cancelator = CancellationToken.create();
+ if (opt?.cancellationToken) {
+ opt.cancellationToken.onCancelled(cancelator.cancel);
+ }
+ this.cancelatorById.set(id, cancelator);
+ this.oc.observe({
+ id,
+ when: AbsoluteTime.now(),
+ type: ObservabilityEventType.HttpFetchStart,
+ url
+ });
+ const optsWithCancel = opt ?? {};
+ optsWithCancel.cancellationToken = cancelator.token;
+ try {
+ const res = await this.impl.fetch(url, optsWithCancel);
+ this.oc.observe({
+ id,
+ when: AbsoluteTime.now(),
+ type: ObservabilityEventType.HttpFetchFinishSuccess,
+ url,
+ status: res.status
+ });
+ return res;
+ } catch (e4) {
+ this.oc.observe({
+ id,
+ when: AbsoluteTime.now(),
+ type: ObservabilityEventType.HttpFetchFinishError,
+ url,
+ error: getErrorDetailFromException(e4)
+ });
+ throw e4;
+ } finally {
+ this.cancelatorById.delete(id);
+ }
+ }
+};
+
// ../taler-util/lib/timer.js
var logger10 = new Logger("timer.ts");
var IntervalHandle = class {
@@ -14489,6 +14264,14 @@ init_hooks_module();
init_preact_module();
init_hooks_module();
init_preact_module();
+init_hooks_module();
+init_preact_module();
+init_hooks_module();
+init_preact_module();
+init_hooks_module();
+init_preact_module();
+init_hooks_module();
+init_preact_module();
init_preact_module();
init_preact_module();
init_hooks_module();
@@ -14879,11 +14662,11 @@ var NOTIFICATION_KEY = "notification";
var GLOBAL_NOTIFICATION_TIMEOUT = Duration.fromSpec({
seconds: 5
});
-function removeFromStorage(n2) {
- const h37 = hash3(n2);
+function updateInStorage(n2) {
+ const h41 = hash3(n2);
const mem = storage3.get(NOTIFICATION_KEY) ?? /* @__PURE__ */ new Map();
const newState = new Map(mem);
- newState.delete(h37);
+ newState.set(h41, n2);
storage3.set(NOTIFICATION_KEY, newState);
}
function notify(notif) {
@@ -14891,7 +14674,8 @@ function notify(notif) {
const newState = currentState.set(hash3(notif), notif);
if (GLOBAL_NOTIFICATION_TIMEOUT.d_ms !== "forever") {
setTimeout(() => {
- removeFromStorage(notif);
+ notif.timeout = true;
+ updateInStorage(notif);
}, GLOBAL_NOTIFICATION_TIMEOUT.d_ms);
}
storage3.set(NOTIFICATION_KEY, newState);
@@ -14901,7 +14685,8 @@ function notifyError(title, description, debug) {
type: "error",
title,
description,
- debug
+ debug,
+ when: AbsoluteTime.now()
});
}
function notifyException(title, ex) {
@@ -14909,28 +14694,31 @@ function notifyException(title, ex) {
type: "error",
title,
description: ex.message,
- debug: ex.stack
+ debug: ex.stack,
+ when: AbsoluteTime.now()
});
}
function notifyInfo(title) {
notify({
type: "info",
- title
+ title,
+ when: AbsoluteTime.now()
});
}
function useNotifications() {
- const [value, setter] = p3(/* @__PURE__ */ new Map());
+ const [, setLastUpdate] = p3();
+ const value = storage3.get(NOTIFICATION_KEY) ?? /* @__PURE__ */ new Map();
h2(() => {
return storage3.onUpdate(NOTIFICATION_KEY, () => {
- const mem = storage3.get(NOTIFICATION_KEY) ?? /* @__PURE__ */ new Map();
- setter(structuredClone(mem));
+ setLastUpdate(Date.now());
});
});
return Array.from(value.values()).map((message, idx) => {
return {
message,
- remove: () => {
- removeFromStorage(message);
+ acknowledge: () => {
+ message.ack = true;
+ updateInStorage(message);
}
};
});
@@ -14964,7 +14752,8 @@ function errorMap(resp, map2) {
type: "error",
title: map2(resp.case),
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
}
function useLocalNotification() {
@@ -14972,7 +14761,7 @@ function useLocalNotification() {
const [value, setter] = p3();
const notif = !value ? void 0 : {
message: value,
- remove: () => {
+ acknowledge: () => {
setter(void 0);
}
};
@@ -14981,7 +14770,7 @@ function useLocalNotification() {
return await cb(errorMap);
} catch (error2) {
if (error2 instanceof TalerError) {
- notify(buildRequestErrorMessage(i18n2, error2));
+ notify(buildUnifiedRequestErrorMessage(i18n2, error2));
} else {
notifyError(
i18n2.str`Operation failed, please report`,
@@ -14996,7 +14785,7 @@ function useLocalNotificationHandler() {
const [value, setter] = p3();
const notif = !value ? void 0 : {
message: value,
- remove: () => {
+ acknowledge: () => {
setter(void 0);
}
};
@@ -15011,15 +14800,36 @@ function useLocalNotificationHandler() {
}
return [notif, makeHandler, setter];
}
-function buildRequestErrorMessage(i18n2, cause) {
+function buildUnifiedRequestErrorMessage(i18n2, cause) {
let result;
switch (cause.errorDetail.code) {
+ case TalerErrorCode.GENERIC_TIMEOUT: {
+ result = {
+ type: "error",
+ title: i18n2.str`Request timeout`,
+ description: cause.message,
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
+ };
+ break;
+ }
+ case TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR: {
+ result = {
+ type: "error",
+ title: i18n2.str`Request cancelled`,
+ description: cause.message,
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
+ };
+ break;
+ }
case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: {
result = {
type: "error",
title: i18n2.str`Request timeout`,
description: cause.message,
- debug: JSON.stringify(cause.errorDetail, void 0, 2)
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
};
break;
}
@@ -15028,7 +14838,8 @@ function buildRequestErrorMessage(i18n2, cause) {
type: "error",
title: i18n2.str`Request throttled`,
description: cause.message,
- debug: JSON.stringify(cause.errorDetail, void 0, 2)
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
};
break;
}
@@ -15037,7 +14848,8 @@ function buildRequestErrorMessage(i18n2, cause) {
type: "error",
title: i18n2.str`Malformed response`,
description: cause.message,
- debug: JSON.stringify(cause.errorDetail, void 0, 2)
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
};
break;
}
@@ -15046,7 +14858,8 @@ function buildRequestErrorMessage(i18n2, cause) {
type: "error",
title: i18n2.str`Network error`,
description: cause.message,
- debug: JSON.stringify(cause.errorDetail, void 0, 2)
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
};
break;
}
@@ -15055,7 +14868,8 @@ function buildRequestErrorMessage(i18n2, cause) {
type: "error",
title: i18n2.str`Unexpected request error`,
description: cause.message,
- debug: JSON.stringify(cause.errorDetail, void 0, 2)
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
};
break;
}
@@ -15064,7 +14878,8 @@ function buildRequestErrorMessage(i18n2, cause) {
type: "error",
title: i18n2.str`Unexpected error`,
description: cause.message,
- debug: JSON.stringify(cause.errorDetail, void 0, 2)
+ debug: JSON.stringify(cause.errorDetail, void 0, 2),
+ when: AbsoluteTime.now()
};
break;
}
@@ -15376,7 +15191,7 @@ function validateURL(baseUrl, endpoint) {
}
}
var logger11 = new Logger("browserHttpLib");
-var BrowserHttpLib = class {
+var BrowserFetchHttpLib = class {
constructor(args) {
this.throttle = new RequestThrottler();
this.throttlingEnabled = true;
@@ -15384,11 +15199,12 @@ var BrowserHttpLib = class {
this.throttlingEnabled = args?.enableThrottling ?? true;
this.requireTls = args?.requireTls ?? false;
}
- fetch(requestUrl, options) {
+ async fetch(requestUrl, options) {
const requestMethod = options?.method ?? "GET";
const requestBody = options?.body;
const requestHeader = options?.headers;
const requestTimeout = options?.timeout ?? Duration.fromMilliseconds(DEFAULT_REQUEST_TIMEOUT_MS);
+ const requestCancel = options?.cancellationToken;
const parsedUrl = new URL(requestUrl);
if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) {
throw TalerError.fromDetail(
@@ -15411,7 +15227,7 @@ var BrowserHttpLib = class {
`request to ${parsedUrl.origin} is not possible with protocol ${parsedUrl.protocol}`
);
}
- let myBody = requestMethod === "POST" || requestMethod === "PUT" || requestMethod === "PATCH" ? encodeBody(requestBody) : void 0;
+ const myBody = requestMethod === "POST" || requestMethod === "PUT" || requestMethod === "PATCH" ? encodeBody(requestBody) : void 0;
const requestHeadersMap = getDefaultHeaders(requestMethod);
if (requestHeader) {
Object.entries(requestHeader).forEach(([key, value]) => {
@@ -15420,138 +15236,139 @@ var BrowserHttpLib = class {
requestHeadersMap[key] = value;
});
}
- return new Promise((resolve, reject) => {
- const myRequest = new XMLHttpRequest();
- myRequest.onerror = (e22) => {
- logger11.error("http request error");
- reject(
- TalerError.fromDetail(
- TalerErrorCode.WALLET_NETWORK_ERROR,
- {
- requestUrl,
- requestMethod
- },
- "Could not make request"
- )
- );
- };
- myRequest.open(requestMethod, requestUrl);
- let timeoutId;
- if (requestTimeout.d_ms !== "forever") {
- timeoutId = setTimeout(() => {
- myRequest.abort();
- reject(
- TalerError.fromDetail(
- TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT,
- {
- requestUrl,
- requestMethod,
- timeoutMs: requestTimeout.d_ms === "forever" ? 0 : requestTimeout.d_ms
- },
- `request to ${requestUrl} timed out`
- )
- );
- }, requestTimeout.d_ms);
+ const controller = new AbortController();
+ let timeoutId;
+ if (requestTimeout.d_ms !== "forever") {
+ timeoutId = setTimeout(() => {
+ controller.abort(TalerErrorCode.GENERIC_TIMEOUT);
+ }, requestTimeout.d_ms);
+ }
+ if (requestCancel) {
+ requestCancel.onCancelled(() => {
+ controller.abort(TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR);
+ });
+ }
+ try {
+ const response = await fetch(requestUrl, {
+ headers: requestHeadersMap,
+ body: myBody,
+ method: requestMethod,
+ signal: controller.signal
+ });
+ if (timeoutId) {
+ clearTimeout(timeoutId);
}
- Object.keys(requestHeadersMap).forEach((headerName) => {
- myRequest.setRequestHeader(headerName, requestHeadersMap[headerName]);
+ const headerMap = new Headers2();
+ response.headers.forEach((value, key) => {
+ headerMap.set(key, value);
});
- myRequest.responseType = "arraybuffer";
- myRequest.send(myBody);
- myRequest.addEventListener("readystatechange", (e22) => {
- if (myRequest.readyState === XMLHttpRequest.DONE) {
- if (myRequest.status === 0) {
- const exc = TalerError.fromDetail(
- TalerErrorCode.WALLET_NETWORK_ERROR,
- {
- requestUrl,
- requestMethod
- },
- "HTTP request failed (status 0, maybe URI scheme was wrong?)"
- );
- reject(exc);
- return;
- }
- const makeText = async () => {
- const td = new TextDecoder();
- return td.decode(myRequest.response);
- };
- let responseJson = void 0;
- const makeJson = async () => {
- if (responseJson === void 0) {
- try {
- const td = new TextDecoder();
- const responseString = td.decode(myRequest.response);
- responseJson = JSON.parse(responseString);
- } catch (e32) {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl,
- requestMethod,
- httpStatusCode: myRequest.status
- },
- "Invalid JSON from HTTP response"
- );
- }
- }
- if (responseJson === null || typeof responseJson !== "object") {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl,
- requestMethod,
- httpStatusCode: myRequest.status
- },
- "Invalid JSON from HTTP response"
- );
- }
- return responseJson;
- };
- const headers = myRequest.getAllResponseHeaders();
- const arr = headers.trim().split(/[\r\n]+/);
- const headerMap = new Headers2();
- arr.forEach(function(line) {
- const parts = line.split(": ");
- const headerName = parts.shift();
- if (!headerName) {
- logger11.warn("skipping invalid header");
- return;
- }
- const value = parts.join(": ");
- headerMap.set(headerName, value);
- });
- const resp = {
+ return {
+ headers: headerMap,
+ status: response.status,
+ requestMethod,
+ requestUrl,
+ json: makeJsonHandler(response, requestUrl, requestMethod),
+ text: makeTextHandler(response, requestUrl, requestMethod),
+ bytes: async () => (await response.blob()).arrayBuffer()
+ };
+ } catch (e22) {
+ if (controller.signal) {
+ throw TalerError.fromDetail(
+ controller.signal.reason,
+ {
requestUrl,
- status: myRequest.status,
- headers: headerMap,
requestMethod,
- json: makeJson,
- text: makeText,
- bytes: async () => myRequest.response
- };
- resolve(resp);
- }
- });
- });
- }
- get(url, opt) {
- return this.fetch(url, {
- method: "GET",
- ...opt
- });
- }
- postJson(url, body, opt) {
- return this.fetch(url, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(body),
- ...opt
- });
- }
- stop() {
+ timeoutMs: requestTimeout.d_ms === "forever" ? 0 : requestTimeout.d_ms
+ },
+ `HTTP request failed.`
+ );
+ }
+ throw e22;
+ }
}
};
+function makeTextHandler(response, requestUrl, requestMethod) {
+ return async function getTextFromResponse() {
+ let respText;
+ try {
+ respText = await response.text();
+ } catch (e22) {
+ throw TalerError.fromDetail(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ {
+ requestUrl,
+ requestMethod,
+ httpStatusCode: response.status
+ },
+ "Invalid text from HTTP response"
+ );
+ }
+ return respText;
+ };
+}
+function makeJsonHandler(response, requestUrl, requestMethod) {
+ let responseJson = void 0;
+ return async function getJsonFromResponse() {
+ if (responseJson === void 0) {
+ try {
+ responseJson = await response.json();
+ } catch (e22) {
+ const message = e22 instanceof Error ? `Invalid JSON from HTTP response: ${e22.message}` : "Invalid JSON from HTTP response";
+ throw TalerError.fromDetail(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ {
+ requestUrl,
+ requestMethod,
+ httpStatusCode: response.status
+ },
+ message
+ );
+ }
+ }
+ if (responseJson === null || typeof responseJson !== "object") {
+ throw TalerError.fromDetail(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ {
+ requestUrl,
+ requestMethod,
+ httpStatusCode: response.status
+ },
+ "Invalid JSON from HTTP response: null or not object"
+ );
+ }
+ return responseJson;
+ };
+}
+function urlPattern(pattern, reverse) {
+ const url = reverse;
+ return {
+ pattern: new RegExp(pattern),
+ url
+ };
+}
+var nullRountDef = {
+ pattern: new RegExp(/.*/),
+ url: () => ""
+};
+function findMatch(pagesMap, pageList, path, params) {
+ for (let idx = 0; idx < pageList.length; idx++) {
+ const name = pageList[idx];
+ const found = pagesMap[name].pattern.exec(path);
+ if (found !== null) {
+ const values = {};
+ Object.entries(params).forEach(([key, value]) => {
+ values[key] = value;
+ });
+ if (found.groups !== void 0) {
+ Object.entries(found.groups).forEach(([key, value]) => {
+ values[key] = value;
+ });
+ }
+ return { name, parent: pagesMap, values };
+ }
+ }
+ return void 0;
+}
var Context = B({ request: defaultRequestHandler });
function buildFormatLongFn(args) {
return function() {
@@ -22701,6 +22518,203 @@ var TranslationProvider = ({
});
};
var useTranslationContext = () => q2(Context2);
+var ActiviyTracker = class {
+ constructor() {
+ this.observers = new Array();
+ }
+ notify(data) {
+ this.observers.forEach((observer) => observer(data));
+ }
+ subscribe(func) {
+ this.observers.push(func);
+ return () => {
+ this.observers.forEach((observer, index) => {
+ if (observer === func) {
+ this.observers.splice(index, 1);
+ }
+ });
+ };
+ }
+};
+var BankContext = B(void 0);
+var useBankCoreApiContext = () => q2(BankContext);
+var BankApiProvider = ({
+ baseUrl,
+ children,
+ frameOnError,
+ evictors = {}
+}) => {
+ const [checked, setChecked] = p3();
+ const { i18n: i18n2 } = useTranslationContext();
+ const { getRemoteConfig, VERSION: VERSION2, lib, cancelRequest, onActivity } = buildBankApiClient(baseUrl, evictors);
+ h2(() => {
+ getRemoteConfig().then((config) => {
+ if (LibtoolVersion.compare(VERSION2, config.version)) {
+ setChecked({ type: "ok", config, hints: [] });
+ } else {
+ setChecked({
+ type: "incompatible",
+ result: config,
+ supported: VERSION2
+ });
+ }
+ }).catch((error2) => {
+ if (error2 instanceof TalerError) {
+ setChecked({ type: "error", error: error2 });
+ }
+ });
+ }, []);
+ if (checked === void 0) {
+ return h(frameOnError, { children: h("div", {}, "checking compatibility with server...") });
+ }
+ if (checked.type === "error") {
+ return h(frameOnError, {
+ children: h(ErrorLoading, { error: checked.error, showDetail: true })
+ });
+ }
+ if (checked.type === "incompatible") {
+ return h(frameOnError, {
+ children: h(
+ "div",
+ {},
+ i18n2.str`The server version is not supported. Supported version "${checked.supported}", server version "${checked.result.version}"`
+ )
+ });
+ }
+ const value = {
+ url: baseUrl,
+ config: checked.config,
+ onActivity,
+ lib,
+ cancelRequest,
+ hints: checked.hints
+ };
+ return h(BankContext.Provider, {
+ value,
+ children
+ });
+};
+function buildBankApiClient(url, evictors) {
+ const httpFetch = new BrowserFetchHttpLib({
+ enableThrottling: true,
+ requireTls: false
+ });
+ const tracker = new ActiviyTracker();
+ const httpLib = new ObservableHttpClientLibrary(httpFetch, {
+ observe(ev) {
+ tracker.notify(ev);
+ }
+ });
+ const bank = new TalerCoreBankHttpClient(
+ url.href,
+ httpLib,
+ evictors.bank
+ );
+ const conversion = new TalerBankConversionHttpClient(
+ bank.getConversionInfoAPI().href,
+ httpLib,
+ evictors.conversion
+ );
+ const auth = (user) => new TalerAuthenticationHttpClient(
+ bank.getAuthenticationAPI(user).href,
+ user,
+ httpLib
+ );
+ async function getRemoteConfig() {
+ const resp = await bank.getConfig();
+ return resp.body;
+ }
+ return {
+ getRemoteConfig,
+ VERSION: bank.PROTOCOL_VERSION,
+ lib: {
+ bank,
+ conversion,
+ auth
+ },
+ onActivity: tracker.subscribe,
+ cancelRequest: httpLib.cancelRequest
+ };
+}
+var MerchantContext = B(void 0);
+function useCurrentLocation(pagesMap) {
+ const pageList = Object.keys(pagesMap);
+ const { path, params } = useNavigationContext();
+ return findMatch(pagesMap, pageList, path, params);
+}
+var Context3 = B(void 0);
+var useNavigationContext = () => q2(Context3);
+function getPathAndParamsFromWindow() {
+ const path = typeof window !== "undefined" ? window.location.hash.substring(1) : "/";
+ const params = {};
+ if (typeof window !== "undefined") {
+ for (const [key, value] of new URLSearchParams(window.location.search)) {
+ params[key] = value;
+ }
+ }
+ return { path, params };
+}
+var { path: initialPath, params: initialParams } = getPathAndParamsFromWindow();
+var PopStateEventType = "popstate";
+var BrowserHashNavigationProvider = ({
+ children
+}) => {
+ const [{ path, params }, setState] = p3({
+ path: initialPath,
+ params: initialParams
+ });
+ if (typeof window === "undefined") {
+ throw Error(
+ "Can't use BrowserHashNavigationProvider if there is no window object"
+ );
+ }
+ function navigateTo(path2) {
+ const { params: params2 } = getPathAndParamsFromWindow();
+ setState({ path: path2, params: params2 });
+ window.location.href = path2;
+ }
+ h2(() => {
+ function eventListener() {
+ setState(getPathAndParamsFromWindow());
+ }
+ window.addEventListener(PopStateEventType, eventListener);
+ return () => {
+ window.removeEventListener(PopStateEventType, eventListener);
+ };
+ }, []);
+ return h(Context3.Provider, {
+ value: { path, params, navigateTo },
+ children
+ });
+};
+function createHeadMetaTag(uri, onNotFound) {
+ const meta = document.createElement("meta");
+ meta.setAttribute("name", "taler-uri");
+ meta.setAttribute("content", stringifyTalerUri(uri));
+ document.head.appendChild(meta);
+ let walletFound = false;
+ window.addEventListener("beforeunload", () => {
+ walletFound = true;
+ });
+ setTimeout(() => {
+ if (!walletFound && onNotFound) {
+ onNotFound();
+ }
+ }, 10);
+}
+var Context4 = B(void 0);
+var useTalerWalletIntegrationAPI = () => q2(Context4);
+var TalerWalletIntegrationBrowserProvider = ({
+ children
+}) => {
+ const value = {
+ publishTalerAction: createHeadMetaTag
+ };
+ return h(Context4.Provider, {
+ value,
+ children
+ });
+};
var utils_exports = {};
__export2(utils_exports, {
compose: () => compose,
@@ -22722,8 +22736,8 @@ function compose(hook, viewMap) {
return ComposedComponent;
}
return (p4) => {
- const h37 = withHook(() => hook(p4));
- return h37();
+ const h41 = withHook(() => hook(p4));
+ return h41();
};
}
function recursive(hook) {
@@ -22739,8 +22753,8 @@ function recursive(hook) {
return ComposedComponent;
}
return (p4) => {
- const h37 = withHook(() => hook(p4));
- return h37();
+ const h41 = withHook(() => hook(p4));
+ return h41();
};
}
function saveVNodeForInspection(obj) {
@@ -22827,7 +22841,7 @@ function CopyIcon() {
function CopiedIcon() {
return /* @__PURE__ */ h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor", class: "w-6 h-6" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M4.5 12.75l6 6 9-13.5" }));
}
-function CopyButton({ class: clazz, getContent }) {
+function CopyButton({ class: clazz, children, getContent }) {
const [copied, setCopied] = p3(false);
function copyText() {
if (!navigator.clipboard && !window.isSecureContext) {
@@ -22846,13 +22860,30 @@ function CopyButton({ class: clazz, getContent }) {
}
}, [copied]);
if (!copied) {
- return /* @__PURE__ */ h("button", { class: clazz, onClick: copyText }, /* @__PURE__ */ h(CopyIcon, null));
+ return /* @__PURE__ */ h("button", { class: clazz, onClick: (e22) => {
+ e22.preventDefault();
+ copyText();
+ } }, /* @__PURE__ */ h(CopyIcon, null), children);
}
- return /* @__PURE__ */ h("button", { class: clazz, disabled: true }, /* @__PURE__ */ h(CopiedIcon, null));
+ return /* @__PURE__ */ h("button", { class: clazz, disabled: true }, /* @__PURE__ */ h(CopiedIcon, null), children);
}
function ErrorLoading({ error: error2, showDetail }) {
const { i18n: i18n2 } = useTranslationContext();
switch (error2.errorDetail.code) {
+ case TalerErrorCode.GENERIC_TIMEOUT: {
+ if (error2.hasErrorCode(TalerErrorCode.GENERIC_TIMEOUT)) {
+ const { requestMethod, requestUrl, timeoutMs } = error2.errorDetail;
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`The request reached a timeout, check your connection.` }, error2.message, showDetail && /* @__PURE__ */ h("pre", { class: "whitespace-break-spaces " }, JSON.stringify({ requestMethod, requestUrl, timeoutMs }, void 0, 2)));
+ }
+ assertUnreachable(1);
+ }
+ case TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR: {
+ if (error2.hasErrorCode(TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR)) {
+ const { requestMethod, requestUrl, timeoutMs } = error2.errorDetail;
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`The request was cancelled.` }, error2.message, showDetail && /* @__PURE__ */ h("pre", { class: "whitespace-break-spaces " }, JSON.stringify({ requestMethod, requestUrl, timeoutMs }, void 0, 2)));
+ }
+ assertUnreachable(1);
+ }
case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: {
if (error2.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT)) {
const { requestMethod, requestUrl, timeoutMs } = error2.errorDetail;
@@ -22975,9 +23006,10 @@ function Spinner() {
return /* @__PURE__ */ h("div", { class: "lds-ring", style: { margin: "auto" } }, /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null));
}
var logo_2021_default = 'data:image/svg+xml,<?xml version="1.0" encoding="UTF-8" standalone="no"?>%0A<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 201 90">%0A <g fill="%230042b3" fill-rule="evenodd" stroke-width=".3">%0A <path d="M86.7 1.1c15.6 0 29 9.4 36 23.2h-5.9A35.1 35.1 0 0086.7 6.5C67 6.5 51 23.6 51 44.7c0 10.4 3.8 19.7 10 26.6a31.4 31.4 0 01-4.2 3A45.2 45.2 0 0146 44.7c0-24 18.2-43.6 40.7-43.6zm35.8 64.3a40.4 40.4 0 01-39 22.8c3-1.5 6-3.5 8.6-5.7a35.6 35.6 0 0024.6-17.1z" />%0A <path d="M64.2 1.1l3.1.1c-3 1.6-5.9 3.5-8.5 5.8a37.5 37.5 0 00-30.2 37.7c0 14.3 7.3 26.7 18 33.3a29.6 29.6 0 01-8.5.2c-9-8-14.6-20-14.6-33.5 0-24 18.2-43.6 40.7-43.6zm5.4 81.4a35.6 35.6 0 0024.6-17.1h5.9a40.4 40.4 0 01-39 22.8c3-1.5 5.9-3.5 8.5-5.7zm24.8-58.2a37 37 0 00-12.6-12.8 29.6 29.6 0 018.5-.2c4 3.6 7.4 8 9.9 13z" />%0A <path d="M41.8 1.1c1 0 2 0 3.1.2-3 1.5-5.9 3.4-8.5 5.6A37.5 37.5 0 006.1 44.7c0 21.1 16 38.3 35.7 38.3 12.6 0 23.6-7 30-17.6h5.8a40.4 40.4 0 01-35.8 23C19.3 88.4 1 68.8 1 44.7c0-24 18.2-43.6 40.7-43.6zm30.1 23.2a38.1 38.1 0 00-4.5-6.1c1.3-1.2 2.7-2.2 4.3-3 2.3 2.7 4.4 5.8 6 9.1z" />%0A </g>%0A <path d="M76.1 34.4h9.2v-5H61.9v5H71v26h5.1zM92.6 52.9h13.7l3 7.4h5.3l-12.7-31.2h-4.7L84.5 60.3h5.2zm11.8-4.9h-9.9l5-12.4zM123.8 29.4h-4.6v31h20.6v-5h-16zM166.5 29.4H145v31h21.6v-5H150v-8.3h14.5v-4.9h-14.5v-8h16.4zM191.2 39.5c0 1.6-.5 2.8-1.6 3.8s-2.6 1.4-4.4 1.4h-7.4V34.3h7.4c1.9 0 3.4.4 4.4 1.3 1 .9 1.6 2.2 1.6 3.9zm6 20.8l-7.7-11.7c1-.3 1.9-.7 2.7-1.3a8.8 8.8 0 003.6-4.6c.4-1 .5-2.2.5-3.5 0-1.5-.2-2.9-.7-4.1a8.4 8.4 0 00-2.1-3.1c-1-.8-2-1.5-3.4-2-1.3-.4-2.8-.6-4.5-.6h-12.9v31h5V49.4h6.5l7 10.8z" />%0A</svg>';
-function Header({ title, profileURL, iconLinkURL, sites, onLogout, children }) {
+function Header({ title, profileURL, notificationURL, iconLinkURL, sites, onLogout, children }) {
const { i18n: i18n2 } = useTranslationContext();
const [open, setOpen] = p3(false);
+ const ns = useNotifications();
return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("header", { class: "bg-indigo-600 w-full mx-auto px-2 border-b border-opacity-25 border-indigo-400" }, /* @__PURE__ */ h("div", { class: "flex flex-row h-16 items-center " }, /* @__PURE__ */ h("div", { class: "flex px-2 justify-start" }, /* @__PURE__ */ h("div", { class: "flex-shrink-0 bg-white rounded-lg" }, /* @__PURE__ */ h("a", { href: iconLinkURL ?? "#", name: "logo" }, /* @__PURE__ */ h(
"img",
{
@@ -22991,7 +23023,7 @@ function Header({ title, profileURL, iconLinkURL, sites, onLogout, children }) {
return;
const [name, url] = site;
return /* @__PURE__ */ h("a", { href: url, name: `site header ${name}`, class: "hidden sm:block text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md py-2 px-3 text-sm font-medium" }, name);
- }))), /* @__PURE__ */ h("div", { class: "flex justify-end" }, !profileURL ? void 0 : /* @__PURE__ */ h("a", { href: profileURL, name: "profile", class: "relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-1 mr-2 text-indigo-200 hover:bg-indigo-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-indigo-600", "aria-controls": "mobile-menu", "aria-expanded": "false" }, /* @__PURE__ */ h("span", { class: "absolute -inset-0.5" }), /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Open profile")), /* @__PURE__ */ h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor", class: "w-10 h-10" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" }))), /* @__PURE__ */ h(
+ }))), /* @__PURE__ */ h("div", { class: "flex justify-end" }, !notificationURL ? void 0 : /* @__PURE__ */ h("a", { href: notificationURL, name: "notifications", class: "relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-1 mr-2 text-indigo-200 hover:bg-indigo-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-indigo-600", "aria-controls": "mobile-menu", "aria-expanded": "false" }, /* @__PURE__ */ h("span", { class: "absolute -inset-0.5" }), /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Show notifications")), ns.length > 0 ? /* @__PURE__ */ h("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", class: "w-10 h-10" }, /* @__PURE__ */ h("path", { d: "M5.85 3.5a.75.75 0 0 0-1.117-1 9.719 9.719 0 0 0-2.348 4.876.75.75 0 0 0 1.479.248A8.219 8.219 0 0 1 5.85 3.5ZM19.267 2.5a.75.75 0 1 0-1.118 1 8.22 8.22 0 0 1 1.987 4.124.75.75 0 0 0 1.48-.248A9.72 9.72 0 0 0 19.266 2.5Z" }), /* @__PURE__ */ h("path", { "fill-rule": "evenodd", d: "M12 2.25A6.75 6.75 0 0 0 5.25 9v.75a8.217 8.217 0 0 1-2.119 5.52.75.75 0 0 0 .298 1.206c1.544.57 3.16.99 4.831 1.243a3.75 3.75 0 1 0 7.48 0 24.583 24.583 0 0 0 4.83-1.244.75.75 0 0 0 .298-1.205 8.217 8.217 0 0 1-2.118-5.52V9A6.75 6.75 0 0 0 12 2.25ZM9.75 18c0-.034 0-.067.002-.1a25.05 25.05 0 0 0 4.496 0l.002.1a2.25 2.25 0 1 1-4.5 0Z", "clip-rule": "evenodd" })) : /* @__PURE__ */ h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor", class: "w-10 h-10" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0" }))), !profileURL ? void 0 : /* @__PURE__ */ h("a", { href: profileURL, name: "profile", class: "relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-1 mr-2 text-indigo-200 hover:bg-indigo-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-indigo-600", "aria-controls": "mobile-menu", "aria-expanded": "false" }, /* @__PURE__ */ h("span", { class: "absolute -inset-0.5" }), /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Open profile")), /* @__PURE__ */ h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor", class: "w-10 h-10" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" }))), /* @__PURE__ */ h(
"button",
{
type: "button",
@@ -23100,7 +23132,8 @@ function Button({
title,
type: "error",
description: error2.detail.hint,
- debug: error2.detail
+ debug: error2.detail,
+ when: AbsoluteTime.now()
});
}
}
@@ -23111,13 +23144,14 @@ function Button({
}).catch((error2) => {
console.error(error2);
if (error2 instanceof TalerError) {
- handler.onNotification(buildRequestErrorMessage(i18n2, error2));
+ handler.onNotification(buildUnifiedRequestErrorMessage(i18n2, error2));
} else {
const description = error2 instanceof Error ? error2.message : String(error2);
handler.onNotification({
title: i18n2.str`Operation failed`,
type: "error",
- description
+ description,
+ when: AbsoluteTime.now()
});
}
if (handler.onOperationComplete) {
@@ -23153,11 +23187,11 @@ function LocalNotificationBanner({ notification, showDebug }) {
switch (notification.message.type) {
case "error":
return /* @__PURE__ */ h("div", { class: "relative" }, /* @__PURE__ */ h("div", { class: "fixed top-0 left-0 right-0 z-20 w-full p-4" }, /* @__PURE__ */ h(Attention, { type: "danger", title: notification.message.title, onClose: () => {
- notification.remove();
+ notification.acknowledge();
} }, notification.message.description && /* @__PURE__ */ h("div", { class: "mt-2 text-sm text-red-700" }, notification.message.description), showDebug && /* @__PURE__ */ h("pre", { class: "whitespace-break-spaces " }, notification.message.debug))));
case "info":
return /* @__PURE__ */ h("div", { class: "relative" }, /* @__PURE__ */ h("div", { class: "fixed top-0 left-0 right-0 z-20 w-full p-4" }, /* @__PURE__ */ h(Attention, { type: "success", title: notification.message.title, onClose: () => {
- notification.remove();
+ notification.acknowledge();
} })));
}
}
@@ -23165,22 +23199,26 @@ function ToastBanner() {
const notifs = useNotifications();
if (notifs.length === 0)
return /* @__PURE__ */ h(p2, null);
- return /* @__PURE__ */ h(p2, null, " ", notifs.map((n2) => {
- switch (n2.message.type) {
- case "error":
- return /* @__PURE__ */ h(Attention, { type: "danger", title: n2.message.title, onClose: () => {
- n2.remove();
- }, timeout: GLOBAL_NOTIFICATION_TIMEOUT }, n2.message.description && /* @__PURE__ */ h("div", { class: "mt-2 text-sm text-red-700" }, n2.message.description));
- case "info":
- return /* @__PURE__ */ h(Attention, { type: "success", title: n2.message.title, onClose: () => {
- n2.remove();
- }, timeout: GLOBAL_NOTIFICATION_TIMEOUT });
- }
- }));
+ const show = notifs.filter((e22) => !e22.message.ack && !e22.message.timeout);
+ if (show.length === 0)
+ return /* @__PURE__ */ h(p2, null);
+ return /* @__PURE__ */ h(AttentionByType, { msg: show[0] });
+}
+function AttentionByType({ msg }) {
+ switch (msg.message.type) {
+ case "error":
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: msg.message.title, onClose: () => {
+ msg.acknowledge();
+ }, timeout: GLOBAL_NOTIFICATION_TIMEOUT }, msg.message.description && /* @__PURE__ */ h("div", { class: "mt-2 text-sm text-red-700" }, msg.message.description));
+ case "info":
+ return /* @__PURE__ */ h(Attention, { type: "success", title: msg.message.title, onClose: () => {
+ msg.acknowledge();
+ }, timeout: GLOBAL_NOTIFICATION_TIMEOUT });
+ }
}
var FormContext = B({});
-// src/components/app.tsx
+// src/app.tsx
init_preact_module();
init_hooks_module();
@@ -24042,12 +24080,114 @@ var useSWR = withArgs(useSWRHandler);
// src/Routing.tsx
init_preact_module();
+init_hooks_module();
-// src/context/config.ts
+// src/hooks/session.ts
+var codecForSessionStateLoggedIn = () => buildCodecForObject().property("status", codecForConstString("loggedIn")).property("username", codecForString()).property("token", codecForString()).property("isUserAdministrator", codecForBoolean()).build("SessionState.LoggedIn");
+var codecForSessionStateExpired = () => buildCodecForObject().property("status", codecForConstString("expired")).property("username", codecForString()).property("isUserAdministrator", codecForBoolean()).build("SessionState.Expired");
+var codecForSessionStateLoggedOut = () => buildCodecForObject().property("status", codecForConstString("loggedOut")).build("SessionState.LoggedOut");
+var codecForSessionState = () => buildCodecForUnion().discriminateOn("status").alternative("loggedIn", codecForSessionStateLoggedIn()).alternative("loggedOut", codecForSessionStateLoggedOut()).alternative("expired", codecForSessionStateExpired()).build("SessionState");
+var defaultState = {
+ status: "loggedOut"
+};
+var SESSION_STATE_KEY = buildStorageKey("bank-session", codecForSessionState());
+function useSessionState() {
+ const { value: state, update } = useLocalStorage(
+ SESSION_STATE_KEY,
+ defaultState
+ );
+ return {
+ state,
+ logOut() {
+ update(defaultState);
+ },
+ expired() {
+ if (state.status === "loggedOut")
+ return;
+ const nextState = {
+ status: "expired",
+ username: state.username,
+ isUserAdministrator: state.username === "admin"
+ };
+ update(nextState);
+ },
+ logIn(info) {
+ const nextState = {
+ status: "loggedIn",
+ ...info,
+ isUserAdministrator: info.username === "admin"
+ };
+ update(nextState);
+ cleanAllCache();
+ }
+ };
+}
+function cleanAllCache() {
+ mutate(() => true, void 0, { revalidate: false });
+}
+
+// src/components/ErrorLoadingWithDebug.tsx
init_preact_module();
-init_hooks_module();
-// src/hooks/access.ts
+// src/hooks/preferences.ts
+var codecForPreferences = () => buildCodecForObject().property("showWithdrawalSuccess", codecForBoolean()).property("showDemoDescription", codecForBoolean()).property("showInstallWallet", codecForBoolean()).property("fastWithdrawal", codecForBoolean()).property("showDebugInfo", codecForBoolean()).property("maxWithdrawalAmount", codecForNumber()).build("Settings");
+var defaultPreferences = {
+ showWithdrawalSuccess: true,
+ showDemoDescription: true,
+ showInstallWallet: true,
+ maxWithdrawalAmount: 25,
+ fastWithdrawal: false,
+ showDebugInfo: false
+};
+var BANK_PREFERENCES_KEY = buildStorageKey(
+ "bank-preferences",
+ codecForPreferences()
+);
+function usePreferences() {
+ const { value, update } = useLocalStorage(
+ BANK_PREFERENCES_KEY,
+ defaultPreferences
+ );
+ function updateField(k5, v3) {
+ const newValue = { ...value, [k5]: v3 };
+ update(newValue);
+ }
+ return [value, updateField];
+}
+function getAllBooleanPreferences() {
+ return [
+ "fastWithdrawal",
+ "showDebugInfo",
+ "showDemoDescription",
+ "showInstallWallet",
+ "showWithdrawalSuccess"
+ ];
+}
+function getLabelForPreferences(k5, i18n2) {
+ switch (k5) {
+ case "maxWithdrawalAmount":
+ return i18n2.str`Max withdrawal amount`;
+ case "showWithdrawalSuccess":
+ return i18n2.str`Show withdrawal confirmation`;
+ case "showDemoDescription":
+ return i18n2.str`Show demo description`;
+ case "showInstallWallet":
+ return i18n2.str`Show install wallet first`;
+ case "fastWithdrawal":
+ return i18n2.str`Use fast withdrawal form`;
+ case "showDebugInfo":
+ return i18n2.str`Show debug info`;
+ }
+}
+
+// src/components/ErrorLoadingWithDebug.tsx
+function ErrorLoadingWithDebug({ error: error2 }) {
+ const [pref] = usePreferences();
+ return /* @__PURE__ */ h(ErrorLoading, { error: error2, showDetail: pref.showDebugInfo });
+}
+
+// src/pages/LoginForm.tsx
+init_preact_module();
init_hooks_module();
// src/utils.ts
@@ -24248,739 +24388,6 @@ function validateTalerBank(account, i18n2) {
return void 0;
}
-// src/hooks/backend.ts
-var codecForBackendStateLoggedIn = () => buildCodecForObject().property("status", codecForConstString("loggedIn")).property("username", codecForString()).property("token", codecForString()).property("isUserAdministrator", codecForBoolean()).build("BackendState.LoggedIn");
-var codecForBackendStateExpired = () => buildCodecForObject().property("status", codecForConstString("expired")).property("username", codecForString()).property("isUserAdministrator", codecForBoolean()).build("BackendState.Expired");
-var codecForBackendStateLoggedOut = () => buildCodecForObject().property("status", codecForConstString("loggedOut")).build("BackendState.LoggedOut");
-var codecForBackendState = () => buildCodecForUnion().discriminateOn("status").alternative("loggedIn", codecForBackendStateLoggedIn()).alternative("loggedOut", codecForBackendStateLoggedOut()).alternative("expired", codecForBackendStateExpired()).build("BackendState");
-var defaultState = {
- status: "loggedOut"
-};
-var BACKEND_STATE_KEY = buildStorageKey("bank-state", codecForBackendState());
-function useBackendState() {
- const { value: state, update } = useLocalStorage(
- BACKEND_STATE_KEY,
- defaultState
- );
- return {
- state,
- logOut() {
- update(defaultState);
- },
- expired() {
- if (state.status === "loggedOut")
- return;
- const nextState = {
- status: "expired",
- username: state.username,
- isUserAdministrator: state.username === "admin"
- };
- update(nextState);
- },
- logIn(info) {
- const nextState = {
- status: "loggedIn",
- ...info,
- isUserAdministrator: info.username === "admin"
- };
- update(nextState);
- cleanAllCache();
- }
- };
-}
-function cleanAllCache() {
- mutate(() => true, void 0, { revalidate: false });
-}
-
-// src/hooks/access.ts
-var useSWR2 = useSWR;
-function revalidateAccountDetails() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getAccount",
- void 0,
- { revalidate: true }
- );
-}
-function useAccountDetails(account) {
- const { state: credentials } = useBackendState();
- const { api } = useBankCoreApiContext();
- async function fetcher([username, token2]) {
- return await api.getAccount({ username, token: token2 });
- }
- const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- const { data, error: error2 } = useSWR2([account, token, "getAccount"], fetcher, {});
- if (data)
- return data;
- if (error2)
- return error2;
- return void 0;
-}
-function useWithdrawalDetails(wid) {
- const { api } = useBankCoreApiContext();
- const [latestStatus, setLatestStatus] = p3();
- async function fetcher([wid2, old_state]) {
- return await api.getWithdrawalById(
- wid2,
- old_state === void 0 ? void 0 : { old_state, timeoutMs: 15e3 }
- );
- }
- const { data, error: error2 } = useSWR2([wid, latestStatus, "getWithdrawalById"], fetcher, {
- refreshInterval: 3e3,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- });
- const currentStatus = data !== void 0 && data.type === "ok" ? data.body.status : void 0;
- h2(() => {
- if (currentStatus !== void 0 && currentStatus !== latestStatus) {
- setLatestStatus(currentStatus);
- }
- }, [currentStatus]);
- if (data)
- return data;
- if (error2)
- return error2;
- return void 0;
-}
-function revalidatePublicAccounts() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getPublicAccounts",
- void 0,
- { revalidate: true }
- );
-}
-function usePublicAccounts(filterAccount, initial4) {
- const [offset, setOffset] = p3(initial4);
- const { api } = useBankCoreApiContext();
- async function fetcher([account, txid]) {
- return await api.getPublicAccounts(
- { account },
- {
- limit: PAGE_SIZE,
- offset: txid ? String(txid) : void 0,
- order: "asc"
- }
- );
- }
- const { data, error: error2 } = useSWR2([filterAccount, offset, "getPublicAccounts"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- });
- const isLastPage = data && data.type === "ok" && data.body.public_accounts.length <= PAGE_SIZE;
- const isFirstPage = !offset;
- const result = data && data.type == "ok" ? structuredClone(data.body.public_accounts) : [];
- if (result.length == PAGE_SIZE + 1) {
- result.pop();
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length)
- return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- }
- };
- if (data) {
- return { ok: true, data: data.body, ...pagination };
- }
- if (error2) {
- return error2;
- }
- return void 0;
-}
-function revalidateTransactions() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getTransactions",
- void 0,
- { revalidate: true }
- );
-}
-function useTransactions(account, initial4) {
- const { state: credentials } = useBackendState();
- const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- const [offset, setOffset] = p3(initial4);
- const { api } = useBankCoreApiContext();
- async function fetcher([username, token2, txid]) {
- return await api.getTransactions(
- { username, token: token2 },
- {
- limit: PAGE_SIZE + 1,
- offset: txid ? String(txid) : void 0,
- order: "dec"
- }
- );
- }
- const { data, error: error2 } = useSWR2([account, token, offset, "getTransactions"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- refreshWhenOffline: false,
- // revalidateOnMount: false,
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false
- });
- const isLastPage = data && data.type === "ok" && data.body.transactions.length <= PAGE_SIZE;
- const isFirstPage = !offset;
- const result = data && data.type == "ok" ? structuredClone(data.body.transactions) : [];
- if (result.length == PAGE_SIZE + 1) {
- result.pop();
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length)
- return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- }
- };
- if (data) {
- return { ok: true, data, ...pagination };
- }
- if (error2) {
- return error2;
- }
- return void 0;
-}
-
-// src/hooks/circuit.ts
-init_hooks_module();
-var useSWR3 = useSWR;
-function revalidateConversionInfo() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getConversionInfoAPI"
- );
-}
-function useConversionInfo() {
- const { api, config } = useBankCoreApiContext();
- async function fetcher() {
- return await api.getConversionInfoAPI().getConfig();
- }
- const { data, error: error2 } = useSWR3(!config.allow_conversion ? void 0 : ["getConversionInfoAPI"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- });
- if (data)
- return data;
- if (error2)
- return error2;
- return void 0;
-}
-function useCashinEstimator() {
- const { api } = useBankCoreApiContext();
- return {
- estimateByCredit: async (fiatAmount, fee) => {
- const resp = await api.getConversionInfoAPI().getCashinRate({
- credit: fiatAmount
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small";
- }
- case HttpStatusCode.NotImplemented:
- case HttpStatusCode.BadRequest:
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.sub(credit, fee).amount;
- return {
- debit,
- beforeFee,
- credit
- };
- },
- estimateByDebit: async (regionalAmount, fee) => {
- const resp = await api.getConversionInfoAPI().getCashinRate({
- debit: regionalAmount
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small";
- }
- case HttpStatusCode.NotImplemented:
- case HttpStatusCode.BadRequest:
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.add(credit, fee).amount;
- return {
- debit,
- beforeFee,
- credit
- };
- }
- };
-}
-function useCashoutEstimator() {
- const { api } = useBankCoreApiContext();
- return {
- estimateByCredit: async (fiatAmount, fee) => {
- const resp = await api.getConversionInfoAPI().getCashoutRate({
- credit: fiatAmount
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small";
- }
- case HttpStatusCode.NotImplemented:
- case HttpStatusCode.BadRequest:
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.sub(credit, fee).amount;
- return {
- debit,
- beforeFee,
- credit
- };
- },
- estimateByDebit: async (regionalAmount, fee) => {
- const resp = await api.getConversionInfoAPI().getCashoutRate({
- debit: regionalAmount
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small";
- }
- case HttpStatusCode.NotImplemented:
- case HttpStatusCode.BadRequest:
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.add(credit, fee).amount;
- return {
- debit,
- beforeFee,
- credit
- };
- }
- };
-}
-function revalidateBusinessAccounts() {
- return mutate((key) => Array.isArray(key) && key[key.length - 1] === "getAccounts", void 0, { revalidate: true });
-}
-function useBusinessAccounts() {
- const { state: credentials } = useBackendState();
- const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- const { api } = useBankCoreApiContext();
- const [offset, setOffset] = p3();
- function fetcher([token2, offset2]) {
- return api.getAccounts(
- token2,
- {},
- {
- limit: PAGE_SIZE + 1,
- offset: String(offset2),
- order: "asc"
- }
- );
- }
- const { data, error: error2 } = useSWR3([token, offset ?? 0, "getAccounts"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- });
- const isLastPage = data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE;
- const isFirstPage = !offset;
- const result = data && data.type == "ok" ? structuredClone(data.body.accounts) : [];
- if (result.length == PAGE_SIZE + 1) {
- result.pop();
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length)
- return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- }
- };
- if (data)
- return { ok: true, data, ...pagination };
- if (error2)
- return error2;
- return void 0;
-}
-function notUndefined(c4) {
- return c4 !== void 0;
-}
-function revalidateCashouts() {
- return mutate((key) => Array.isArray(key) && key[key.length - 1] === "useCashouts");
-}
-function useCashouts(account) {
- const { state: credentials } = useBackendState();
- const { api, config } = useBankCoreApiContext();
- const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- async function fetcher([username, token2]) {
- const list = await api.getAccountCashouts({ username, token: token2 });
- if (list.type !== "ok") {
- return list;
- }
- const all = await Promise.all(
- list.body.cashouts.map(async (c4) => {
- const r3 = await api.getCashoutById({ username, token: token2 }, c4.cashout_id);
- if (r3.type === "fail") {
- return void 0;
- }
- return { ...r3.body, id: c4.cashout_id };
- })
- );
- const cashouts = all.filter(notUndefined);
- return { type: "ok", body: { cashouts }, httpResp: list.httpResp };
- }
- const { data, error: error2 } = useSWR3(
- !config.allow_conversion ? void 0 : [account, token, "useCashouts"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- }
- );
- if (data)
- return data;
- if (error2)
- return error2;
- return void 0;
-}
-function useCashoutDetails(cashoutId) {
- const { state: credentials } = useBackendState();
- const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
- const { api } = useBankCoreApiContext();
- async function fetcher([username, token, id]) {
- return api.getCashoutById({ username, token }, id);
- }
- const { data, error: error2 } = useSWR3(
- cashoutId === void 0 ? void 0 : [creds?.username, creds?.token, cashoutId, "getCashoutById"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- }
- );
- if (data)
- return data;
- if (error2)
- return error2;
- return void 0;
-}
-function useLastMonitorInfo(currentMoment, previousMoment, timeframe) {
- const { api } = useBankCoreApiContext();
- const { state: credentials } = useBackendState();
- const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- async function fetcher([token2, timeframe2]) {
- const [current, previous] = await Promise.all([
- api.getMonitor(token2, { timeframe: timeframe2, which: currentMoment }),
- api.getMonitor(token2, { timeframe: timeframe2, which: previousMoment })
- ]);
- return {
- current,
- previous
- };
- }
- const { data, error: error2 } = useSWR3(
- !token ? void 0 : [token, timeframe, "useLastMonitorInfo"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true
- }
- );
- if (data)
- return data;
- if (error2)
- return error2;
- return void 0;
-}
-
-// src/context/config.ts
-var Context3 = B(void 0);
-var useBankCoreApiContext = () => q2(Context3);
-var BankCoreApiProvider = ({
- baseUrl,
- children,
- frameOnError
-}) => {
- const [checked, setChecked] = p3();
- const { i18n: i18n2 } = useTranslationContext();
- const url = new URL(baseUrl);
- const api = new CacheAwareTalerCoreBankHttpClient(url.href, new BrowserHttpLib());
- h2(() => {
- api.getConfig().then((resp) => {
- if (api.isCompatible(resp.body.version)) {
- setChecked({ type: "ok", config: resp.body, hints: [] });
- } else {
- const compare2 = LibtoolVersion.compare("3:0:3", resp.body.version);
- if (compare2?.compatible ?? false) {
- setChecked({
- type: "ok",
- config: resp.body,
- hints: [0 /* CASHOUT_BEFORE_2FA */]
- });
- } else {
- setChecked({
- type: "incompatible",
- result: resp.body,
- supported: api.PROTOCOL_VERSION
- });
- }
- }
- }).catch((error2) => {
- if (error2 instanceof TalerError) {
- setChecked({ type: "error", error: error2 });
- }
- });
- }, []);
- if (checked === void 0) {
- return h(frameOnError, { children: h("div", {}, "loading...") });
- }
- if (checked.type === "error") {
- return h(frameOnError, {
- children: h(ErrorLoading, { error: checked.error, showDetail: true })
- });
- }
- if (checked.type === "incompatible") {
- return h(frameOnError, {
- children: h(
- "div",
- {},
- i18n2.str`The bank backend is not supported. Supported version "${checked.supported}", server version "${checked.result.version}"`
- )
- });
- }
- const value = {
- url,
- config: checked.config,
- api,
- hints: checked.hints
- };
- return h(Context3.Provider, {
- value,
- children
- });
-};
-var CacheAwareTalerBankConversionHttpClient = class extends TalerBankConversionHttpClient {
- constructor(baseUrl, httpClient) {
- super(baseUrl, httpClient);
- }
- async updateConversionRate(auth, body) {
- const resp = await super.updateConversionRate(auth, body);
- if (resp.type === "ok") {
- await revalidateConversionInfo();
- }
- return resp;
- }
-};
-var CacheAwareTalerCoreBankHttpClient = class extends TalerCoreBankHttpClient {
- constructor(baseUrl, httpClient) {
- super(baseUrl, httpClient);
- }
- async deleteAccount(auth, cid) {
- const resp = await super.deleteAccount(auth, cid);
- if (resp.type === "ok") {
- await revalidatePublicAccounts();
- await revalidateBusinessAccounts();
- }
- return resp;
- }
- async createAccount(auth, body) {
- const resp = await super.createAccount(auth, body);
- if (resp.type === "ok") {
- await revalidateAccountDetails();
- await revalidateTransactions();
- await revalidatePublicAccounts();
- await revalidateBusinessAccounts();
- }
- return resp;
- }
- async updateAccount(auth, body, cid) {
- const resp = await super.updateAccount(auth, body, cid);
- if (resp.type === "ok") {
- await revalidateAccountDetails();
- }
- return resp;
- }
- async createTransaction(auth, body, cid) {
- const resp = await super.createTransaction(auth, body, cid);
- if (resp.type === "ok") {
- await revalidateAccountDetails();
- await revalidateTransactions();
- }
- return resp;
- }
- async confirmWithdrawalById(auth, wid, cid) {
- const resp = await super.confirmWithdrawalById(auth, wid, cid);
- if (resp.type === "ok") {
- await revalidateAccountDetails();
- await revalidateTransactions();
- }
- return resp;
- }
- async createCashout(auth, body, cid) {
- const resp = await super.createCashout(auth, body, cid);
- if (resp.type === "ok") {
- await revalidateAccountDetails();
- await revalidateCashouts();
- await revalidateTransactions();
- }
- return resp;
- }
- getConversionInfoAPI() {
- const api = super.getConversionInfoAPI();
- return new CacheAwareTalerBankConversionHttpClient(api.baseUrl, this.httpLib);
- }
-};
-
-// src/context/settings.ts
-init_preact_module();
-init_hooks_module();
-var initial2 = {};
-var Context4 = B(initial2);
-var useSettingsContext = () => q2(Context4);
-var SettingsProvider = ({
- children,
- value
-}) => {
- return h(Context4.Provider, {
- value,
- children
- });
-};
-
-// src/components/ErrorLoadingWithDebug.tsx
-init_preact_module();
-
-// src/hooks/preferences.ts
-function getAllBooleanPreferences() {
- return [
- "fastWithdrawal",
- "showDebugInfo",
- "showDemoDescription",
- "showInstallWallet",
- "showWithdrawalSuccess"
- ];
-}
-function getLabelForPreferences(k5, i18n2) {
- switch (k5) {
- case "maxWithdrawalAmount":
- return i18n2.str`Max withdrawal amount`;
- case "showWithdrawalSuccess":
- return i18n2.str`Show withdrawal confirmation`;
- case "showDemoDescription":
- return i18n2.str`Show demo description`;
- case "showInstallWallet":
- return i18n2.str`Show install wallet first`;
- case "fastWithdrawal":
- return i18n2.str`Use fast withdrawal form`;
- case "showDebugInfo":
- return i18n2.str`Show debug info`;
- }
-}
-var codecForPreferences = () => buildCodecForObject().property("showWithdrawalSuccess", codecForBoolean()).property("showDemoDescription", codecForBoolean()).property("showInstallWallet", codecForBoolean()).property("fastWithdrawal", codecForBoolean()).property("showDebugInfo", codecForBoolean()).property("maxWithdrawalAmount", codecForNumber()).build("Settings");
-var defaultPreferences = {
- showWithdrawalSuccess: true,
- showDemoDescription: true,
- showInstallWallet: true,
- maxWithdrawalAmount: 25,
- fastWithdrawal: false,
- showDebugInfo: false
-};
-var BANK_PREFERENCES_KEY = buildStorageKey(
- "bank-preferences",
- codecForPreferences()
-);
-function usePreferences() {
- const { value, update } = useLocalStorage(
- BANK_PREFERENCES_KEY,
- defaultPreferences
- );
- function updateField(k5, v3) {
- const newValue = { ...value, [k5]: v3 };
- update(newValue);
- }
- return [value, updateField];
-}
-
-// src/components/ErrorLoadingWithDebug.tsx
-function ErrorLoadingWithDebug({ error: error2 }) {
- const [pref] = usePreferences();
- return /* @__PURE__ */ h(ErrorLoading, { error: error2, showDetail: pref.showDebugInfo });
-}
-
-// src/pages/LoginForm.tsx
-init_preact_module();
-init_hooks_module();
-
// src/pages/PaytoWireTransferForm.tsx
init_preact_module();
init_hooks_module();
@@ -25015,7 +24422,6 @@ function useBankState() {
// src/pages/PaytoWireTransferForm.tsx
function PaytoWireTransferForm({
focus,
- title,
withAccount,
withSubject,
withAmount,
@@ -25026,9 +24432,10 @@ function PaytoWireTransferForm({
onAuthorizationRequired,
limit
}) {
- const [isRawPayto, setIsRawPayto] = p3(false);
- const { state: credentials } = useBackendState();
- const { api, config, url } = useBankCoreApiContext();
+ const [inputType, setInputType] = p3("form");
+ const isRawPayto = inputType !== "form";
+ const { state: credentials } = useSessionState();
+ const { lib: { bank: api }, config, url } = useBankCoreApiContext();
const sendingToFixedAccount = withAccount !== void 0;
const [account, setAccount] = p3(withAccount);
const [subject, setSubject] = p3(withSubject);
@@ -25056,6 +24463,7 @@ function PaytoWireTransferForm({
let sendingAmount;
if (credentials.status !== "loggedIn")
return;
+ let acName;
if (isRawPayto) {
const p4 = parsePaytoUri(rawPaytoInput);
if (!p4)
@@ -25063,10 +24471,12 @@ function PaytoWireTransferForm({
sendingAmount = p4.params.amount;
delete p4.params.amount;
payto_uri = stringifyPaytoUri(p4);
+ acName = !p4.isKnown ? void 0 : p4.targetType === "iban" ? p4.iban : p4.targetType === "bitcoin" ? p4.address : p4.targetType === "x-taler-bank" ? p4.account : assertUnreachable(p4);
} else {
if (!account || !subject)
return;
let payto;
+ acName = account;
switch (paytoType) {
case "x-taler-bank": {
payto = buildPayto("x-taler-bank", url.host, account);
@@ -25099,48 +24509,66 @@ function PaytoWireTransferForm({
type: "error",
title: i18n2.str`The request was invalid or the payto://-URI used unacceptable features.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Unauthorized:
return notify2({
type: "error",
title: i18n2.str`Not enough permission to complete the operation.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
+ });
+ case TalerErrorCode.BANK_ADMIN_CREDITOR:
+ return notify2({
+ type: "error",
+ title: i18n2.str`Bank administrator can't be the transfer creditor.`,
+ description: resp.detail.hint,
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_UNKNOWN_CREDITOR:
return notify2({
type: "error",
- title: i18n2.str`The destination account "${puri}" was not found.`,
+ title: i18n2.str`The destination account "${acName ?? puri}" was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_SAME_ACCOUNT:
return notify2({
type: "error",
title: i18n2.str`The origin and the destination of the transfer can't be the same.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return notify2({
type: "error",
title: i18n2.str`Your balance is not enough.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The origin account "${puri}" was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Accepted: {
updateBankState("currentChallenge", {
operation: "create-transaction",
id: String(resp.body.challenge_id),
- location: routeHere.url({ account: account ?? "", amount, subject }),
+ location: routeHere.url({
+ account: account ?? "",
+ amount,
+ subject
+ }),
sent: AbsoluteTime.never(),
request
});
@@ -25158,20 +24586,17 @@ function PaytoWireTransferForm({
rawPaytoInputSetter(void 0);
});
}
- return /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, title), /* @__PURE__ */ h("div", { class: "px-2 mt-2 grid grid-cols-1 gap-y-4 sm:gap-x-4" }, /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 my-4 md:grid-cols-3 bg-gray-100 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("fieldset", { class: "px-2 grid grid-cols-1 gap-y-4 sm:gap-x-4" }, /* @__PURE__ */ h("legend", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Input wire transfer detail")), /* @__PURE__ */ h("div", { class: "-space-y-px rounded-md " }, /* @__PURE__ */ h(
"label",
{
- class: "relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (!isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")
+ "data-checked": inputType === "form",
+ class: "group rounded-tl-md rounded-tr-md relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50"
},
/* @__PURE__ */ h(
"input",
{
type: "radio",
- name: "project-type",
- value: "Newsletter",
- class: "sr-only",
- "aria-labelledby": "project-type-0-label",
- "aria-describedby": "project-type-0-description-0 project-type-0-description-1",
+ name: "input-type",
onChange: () => {
if (parsed && parsed.isKnown) {
switch (parsed.targetType) {
@@ -25202,60 +24627,94 @@ function PaytoWireTransferForm({
setSubject(subject2);
}
}
- setIsRawPayto(false);
- }
+ setInputType("form");
+ },
+ checked: inputType === "form",
+ value: "form",
+ class: "mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600"
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Using a form"))))
+ /* @__PURE__ */ h("span", { class: "ml-3 flex flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ "data-checked": inputType === "form",
+ class: "block text-sm font-medium data-[checked=true]:text-indigo-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Using a form")
+ ))
), sendingToFixedAccount ? void 0 : /* @__PURE__ */ h(
- "label",
- {
- class: "relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")
- },
+ p2,
+ null,
/* @__PURE__ */ h(
- "input",
+ "label",
{
- type: "radio",
- name: "project-type",
- value: "Existing Customers",
- class: "sr-only",
- "aria-labelledby": "project-type-1-label",
- "aria-describedby": "project-type-1-description-0 project-type-1-description-1",
- onChange: () => {
- if (account) {
- let payto;
- switch (paytoType) {
- case "x-taler-bank": {
- payto = buildPayto("x-taler-bank", url.host, account);
- if (parsedAmount) {
- payto.params["amount"] = Amounts.stringify(parsedAmount);
- }
- if (subject) {
- payto.params["message"] = subject;
- }
- break;
- }
- case "iban": {
- payto = buildPayto("iban", account, void 0);
- if (parsedAmount) {
- payto.params["amount"] = Amounts.stringify(parsedAmount);
+ "data-checked": inputType === "payto",
+ class: "relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50"
+ },
+ /* @__PURE__ */ h(
+ "input",
+ {
+ type: "radio",
+ name: "input-type",
+ onChange: () => {
+ if (account) {
+ let payto;
+ switch (paytoType) {
+ case "x-taler-bank": {
+ payto = buildPayto(
+ "x-taler-bank",
+ url.host,
+ account
+ );
+ if (parsedAmount) {
+ payto.params["amount"] = Amounts.stringify(parsedAmount);
+ }
+ if (subject) {
+ payto.params["message"] = subject;
+ }
+ break;
}
- if (subject) {
- payto.params["message"] = subject;
+ case "iban": {
+ payto = buildPayto("iban", account, void 0);
+ if (parsedAmount) {
+ payto.params["amount"] = Amounts.stringify(parsedAmount);
+ }
+ if (subject) {
+ payto.params["message"] = subject;
+ }
+ break;
}
- break;
+ default:
+ assertUnreachable(paytoType);
}
- default:
- assertUnreachable(paytoType);
+ rawPaytoInputSetter(stringifyPaytoUri(payto));
}
- rawPaytoInputSetter(stringifyPaytoUri(payto));
- }
- setIsRawPayto(true);
+ setInputType("payto");
+ },
+ checked: inputType === "payto",
+ value: "payto",
+ class: "mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600"
}
- }
+ ),
+ /* @__PURE__ */ h("span", { class: "ml-3 flex flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ "data-checked": inputType === "payto",
+ class: "block font-medium data-[checked=true]:text-indigo-900"
+ },
+ "payto:// URI"
+ ), /* @__PURE__ */ h(
+ "span",
+ {
+ "data-checked": inputType === "payto",
+ class: "block text-sm text-gray-500 data-[checked=true]:text-indigo-600"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "A special URI that indicate the transfer amount and account target.")
+ ))
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Import payto:// URI"))))
- ), routeCashout ? /* @__PURE__ */ h(
+ //FIXME: add QR support
+ false
+ )), routeCashout ? /* @__PURE__ */ h(
"a",
{
name: "do cashout",
@@ -25280,6 +24739,7 @@ function PaytoWireTransferForm({
TextField,
{
id: "x-taler-bank",
+ required: true,
label: i18n2.str`Recipient`,
help: i18n2.str`Id of the recipient's account`,
error: errorsWire?.account,
@@ -25296,6 +24756,7 @@ function PaytoWireTransferForm({
TextField,
{
id: "iban",
+ required: true,
label: i18n2.str`Recipient`,
help: i18n2.str`IBAN of the recipient's account`,
placeholder: "CC0123456789",
@@ -25316,7 +24777,8 @@ function PaytoWireTransferForm({
for: "subject",
class: "block text-sm font-medium leading-6 text-gray-900"
},
- i18n2.str`Transfer subject`
+ i18n2.str`Transfer subject`,
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
"input",
{
@@ -25344,7 +24806,8 @@ function PaytoWireTransferForm({
for: "amount",
class: "block text-sm font-medium leading-6 text-gray-900"
},
- i18n2.str`Amount`
+ i18n2.str`Amount`,
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
), /* @__PURE__ */ h(
InputAmount,
{
@@ -25368,7 +24831,8 @@ function PaytoWireTransferForm({
for: "address",
class: "block text-sm font-medium leading-6 text-gray-900"
},
- i18n2.str`Payto URI:`
+ i18n2.str`Payto URI:`,
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
"textarea",
{
@@ -25572,7 +25036,10 @@ function validateSubject(text, i18n2) {
}
return void 0;
}
-function Wrapper({ withIcon, children }) {
+function Wrapper({
+ withIcon,
+ children
+}) {
if (withIcon) {
return /* @__PURE__ */ h("div", { class: "flex justify-between" }, children);
}
@@ -25587,17 +25054,11 @@ function TextField({
onChange,
placeholder,
rightIcons,
+ required,
value,
error: error2
}) {
- return /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
- "label",
- {
- for: id,
- class: "block text-sm font-medium leading-6 text-gray-900"
- },
- label
- ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(Wrapper, { withIcon: rightIcons !== void 0 }, /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("label", { for: id, class: "block text-sm font-medium leading-6 text-gray-900" }, label, required && /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(Wrapper, { withIcon: rightIcons !== void 0 }, /* @__PURE__ */ h(
"input",
{
ref: focus ? doAutoFocus : void 0,
@@ -25614,13 +25075,3192 @@ function TextField({
onChange(e4.currentTarget.value);
}
}
- ), rightIcons), /* @__PURE__ */ h(
- ShowInputErrorLabel,
+ ), rightIcons), /* @__PURE__ */ h(ShowInputErrorLabel, { message: error2, isDirty: value !== void 0 })), help && /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, help));
+}
+
+// src/pages/RegistrationPage.tsx
+init_preact_module();
+init_hooks_module();
+
+// src/context/settings.ts
+init_preact_module();
+init_hooks_module();
+var initial2 = {};
+var Context5 = B(initial2);
+var useSettingsContext = () => q2(Context5);
+var SettingsProvider = ({
+ children,
+ value
+}) => {
+ return h(Context5.Provider, {
+ value,
+ children
+ });
+};
+
+// src/pages/rnd.ts
+var noun = [
+ "people",
+ "history",
+ "way",
+ "art",
+ "world",
+ "information",
+ "map",
+ "two",
+ "family",
+ "government",
+ "health",
+ "system",
+ "computer",
+ "meat",
+ "year",
+ "thanks",
+ "music",
+ "person",
+ "reading",
+ "method",
+ "data",
+ "food",
+ "understanding",
+ "theory",
+ "law",
+ "bird",
+ "literature",
+ "problem",
+ "software",
+ "control",
+ "knowledge",
+ "power",
+ "ability",
+ "economics",
+ "love",
+ "internet",
+ "television",
+ "science",
+ "library",
+ "nature",
+ "fact",
+ "product",
+ "idea",
+ "temperature",
+ "investment",
+ "area",
+ "society",
+ "activity",
+ "story",
+ "industry",
+ "media",
+ "thing",
+ "oven",
+ "community",
+ "definition",
+ "safety",
+ "quality",
+ "development",
+ "language",
+ "management",
+ "player",
+ "variety",
+ "video",
+ "week",
+ "security",
+ "country",
+ "exam",
+ "movie",
+ "organization",
+ "equipment",
+ "physics",
+ "analysis",
+ "policy",
+ "series",
+ "thought",
+ "basis",
+ "boyfriend",
+ "direction",
+ "strategy",
+ "technology",
+ "army",
+ "camera",
+ "freedom",
+ "paper",
+ "environment",
+ "child",
+ "instance",
+ "month",
+ "truth",
+ "marketing",
+ "university",
+ "writing",
+ "article",
+ "department",
+ "difference",
+ "goal",
+ "news",
+ "audience",
+ "fishing",
+ "growth",
+ "income",
+ "marriage",
+ "user",
+ "combination",
+ "failure",
+ "meaning",
+ "medicine",
+ "philosophy",
+ "teacher",
+ "communication",
+ "night",
+ "chemistry",
+ "disease",
+ "disk",
+ "energy",
+ "nation",
+ "road",
+ "role",
+ "soup",
+ "advertising",
+ "location",
+ "success",
+ "addition",
+ "apartment",
+ "education",
+ "math",
+ "moment",
+ "painting",
+ "politics",
+ "attention",
+ "decision",
+ "event",
+ "property",
+ "shopping",
+ "student",
+ "wood",
+ "competition",
+ "distribution",
+ "entertainment",
+ "office",
+ "population",
+ "president",
+ "unit",
+ "category",
+ "cigarette",
+ "context",
+ "introduction",
+ "opportunity",
+ "performance",
+ "driver",
+ "flight",
+ "length",
+ "magazine",
+ "newspaper",
+ "relationship",
+ "teaching",
+ "cell",
+ "dealer",
+ "finding",
+ "lake",
+ "member",
+ "message",
+ "phone",
+ "scene",
+ "appearance",
+ "association",
+ "concept",
+ "customer",
+ "death",
+ "discussion",
+ "housing",
+ "inflation",
+ "insurance",
+ "mood",
+ "woman",
+ "advice",
+ "blood",
+ "effort",
+ "expression",
+ "importance",
+ "opinion",
+ "payment",
+ "reality",
+ "responsibility",
+ "situation",
+ "skill",
+ "statement",
+ "wealth",
+ "application",
+ "city",
+ "county",
+ "depth",
+ "estate",
+ "foundation",
+ "grandmother",
+ "heart",
+ "perspective",
+ "photo",
+ "recipe",
+ "studio",
+ "topic",
+ "collection",
+ "depression",
+ "imagination",
+ "passion",
+ "percentage",
+ "resource",
+ "setting",
+ "ad",
+ "agency",
+ "college",
+ "connection",
+ "criticism",
+ "debt",
+ "description",
+ "memory",
+ "patience",
+ "secretary",
+ "solution",
+ "administration",
+ "aspect",
+ "attitude",
+ "director",
+ "personality",
+ "psychology",
+ "recommendation",
+ "response",
+ "selection",
+ "storage",
+ "version",
+ "alcohol",
+ "argument",
+ "complaint",
+ "contract",
+ "emphasis",
+ "highway",
+ "loss",
+ "membership",
+ "possession",
+ "preparation",
+ "steak",
+ "union",
+ "agreement",
+ "cancer",
+ "currency",
+ "employment",
+ "engineering",
+ "entry",
+ "interaction",
+ "mixture",
+ "preference",
+ "region",
+ "republic",
+ "tradition",
+ "virus",
+ "actor",
+ "classroom",
+ "delivery",
+ "device",
+ "difficulty",
+ "drama",
+ "election",
+ "engine",
+ "football",
+ "guidance",
+ "hotel",
+ "owner",
+ "priority",
+ "protection",
+ "suggestion",
+ "tension",
+ "variation",
+ "anxiety",
+ "atmosphere",
+ "awareness",
+ "bath",
+ "bread",
+ "candidate",
+ "climate",
+ "comparison",
+ "confusion",
+ "construction",
+ "elevator",
+ "emotion",
+ "employee",
+ "employer",
+ "guest",
+ "height",
+ "leadership",
+ "mall",
+ "manager",
+ "operation",
+ "recording",
+ "sample",
+ "transportation",
+ "charity",
+ "cousin",
+ "disaster",
+ "editor",
+ "efficiency",
+ "excitement",
+ "extent",
+ "feedback",
+ "guitar",
+ "homework",
+ "leader",
+ "mom",
+ "outcome",
+ "permission",
+ "presentation",
+ "promotion",
+ "reflection",
+ "refrigerator",
+ "resolution",
+ "revenue",
+ "session",
+ "singer",
+ "tennis",
+ "basket",
+ "bonus",
+ "cabinet",
+ "childhood",
+ "church",
+ "clothes",
+ "coffee",
+ "dinner",
+ "drawing",
+ "hair",
+ "hearing",
+ "initiative",
+ "judgment",
+ "lab",
+ "measurement",
+ "mode",
+ "mud",
+ "orange",
+ "poetry",
+ "police",
+ "possibility",
+ "procedure",
+ "queen",
+ "ratio",
+ "relation",
+ "restaurant",
+ "satisfaction",
+ "sector",
+ "signature",
+ "significance",
+ "song",
+ "tooth",
+ "town",
+ "vehicle",
+ "volume",
+ "wife",
+ "accident",
+ "airport",
+ "appointment",
+ "arrival",
+ "assumption",
+ "baseball",
+ "chapter",
+ "committee",
+ "conversation",
+ "database",
+ "enthusiasm",
+ "error",
+ "explanation",
+ "farmer",
+ "gate",
+ "girl",
+ "hall",
+ "historian",
+ "hospital",
+ "injury",
+ "instruction",
+ "maintenance",
+ "manufacturer",
+ "meal",
+ "perception",
+ "pie",
+ "poem",
+ "presence",
+ "proposal",
+ "reception",
+ "replacement",
+ "revolution",
+ "river",
+ "son",
+ "speech",
+ "tea",
+ "village",
+ "warning",
+ "winner",
+ "worker",
+ "writer",
+ "assistance",
+ "breath",
+ "buyer",
+ "chest",
+ "chocolate",
+ "conclusion",
+ "contribution",
+ "cookie",
+ "courage",
+ "dad",
+ "desk",
+ "drawer",
+ "establishment",
+ "examination",
+ "garbage",
+ "grocery",
+ "honey",
+ "impression",
+ "improvement",
+ "independence",
+ "insect",
+ "inspection",
+ "inspector",
+ "king",
+ "ladder",
+ "menu",
+ "penalty",
+ "piano",
+ "potato",
+ "profession",
+ "professor",
+ "quantity",
+ "reaction",
+ "requirement",
+ "salad",
+ "sister",
+ "supermarket",
+ "tongue",
+ "weakness",
+ "wedding",
+ "affair",
+ "ambition",
+ "analyst",
+ "apple",
+ "assignment",
+ "assistant",
+ "bathroom",
+ "bedroom",
+ "beer",
+ "birthday",
+ "celebration",
+ "championship",
+ "cheek",
+ "client",
+ "consequence",
+ "departure",
+ "diamond",
+ "dirt",
+ "ear",
+ "fortune",
+ "friendship",
+ "funeral",
+ "gene",
+ "girlfriend",
+ "hat",
+ "indication",
+ "intention",
+ "lady",
+ "midnight",
+ "negotiation",
+ "obligation",
+ "passenger",
+ "pizza",
+ "platform",
+ "poet",
+ "pollution",
+ "recognition",
+ "reputation",
+ "shirt",
+ "sir",
+ "speaker",
+ "stranger",
+ "surgery",
+ "sympathy",
+ "tale",
+ "throat",
+ "trainer",
+ "uncle",
+ "youth",
+ "time",
+ "work",
+ "film",
+ "water",
+ "money",
+ "example",
+ "while",
+ "business",
+ "study",
+ "game",
+ "life",
+ "form",
+ "air",
+ "day",
+ "place",
+ "number",
+ "part",
+ "field",
+ "fish",
+ "back",
+ "process",
+ "heat",
+ "hand",
+ "experience",
+ "job",
+ "book",
+ "end",
+ "point",
+ "type",
+ "home",
+ "economy",
+ "value",
+ "body",
+ "market",
+ "guide",
+ "interest",
+ "state",
+ "radio",
+ "course",
+ "company",
+ "price",
+ "size",
+ "card",
+ "list",
+ "mind",
+ "trade",
+ "line",
+ "care",
+ "group",
+ "risk",
+ "word",
+ "fat",
+ "force",
+ "key",
+ "light",
+ "training",
+ "name",
+ "school",
+ "top",
+ "amount",
+ "level",
+ "order",
+ "practice",
+ "research",
+ "sense",
+ "service",
+ "piece",
+ "web",
+ "boss",
+ "sport",
+ "fun",
+ "house",
+ "page",
+ "term",
+ "test",
+ "answer",
+ "sound",
+ "focus",
+ "matter",
+ "kind",
+ "soil",
+ "board",
+ "oil",
+ "picture",
+ "access",
+ "garden",
+ "range",
+ "rate",
+ "reason",
+ "future",
+ "site",
+ "demand",
+ "exercise",
+ "image",
+ "case",
+ "cause",
+ "coast",
+ "action",
+ "age",
+ "bad",
+ "boat",
+ "record",
+ "result",
+ "section",
+ "building",
+ "mouse",
+ "cash",
+ "class",
+ "nothing",
+ "period",
+ "plan",
+ "store",
+ "tax",
+ "side",
+ "subject",
+ "space",
+ "rule",
+ "stock",
+ "weather",
+ "chance",
+ "figure",
+ "man",
+ "model",
+ "source",
+ "beginning",
+ "earth",
+ "program",
+ "chicken",
+ "design",
+ "feature",
+ "head",
+ "material",
+ "purpose",
+ "question",
+ "rock",
+ "salt",
+ "act",
+ "birth",
+ "car",
+ "dog",
+ "object",
+ "scale",
+ "sun",
+ "note",
+ "profit",
+ "rent",
+ "speed",
+ "style",
+ "war",
+ "bank",
+ "craft",
+ "half",
+ "inside",
+ "outside",
+ "standard",
+ "bus",
+ "exchange",
+ "eye",
+ "fire",
+ "position",
+ "pressure",
+ "stress",
+ "advantage",
+ "benefit",
+ "box",
+ "frame",
+ "issue",
+ "step",
+ "cycle",
+ "face",
+ "item",
+ "metal",
+ "paint",
+ "review",
+ "room",
+ "screen",
+ "structure",
+ "view",
+ "account",
+ "ball",
+ "discipline",
+ "medium",
+ "share",
+ "balance",
+ "bit",
+ "black",
+ "bottom",
+ "choice",
+ "gift",
+ "impact",
+ "machine",
+ "shape",
+ "tool",
+ "wind",
+ "address",
+ "average",
+ "career",
+ "culture",
+ "morning",
+ "pot",
+ "sign",
+ "table",
+ "task",
+ "condition",
+ "contact",
+ "credit",
+ "egg",
+ "hope",
+ "ice",
+ "network",
+ "north",
+ "square",
+ "attempt",
+ "date",
+ "effect",
+ "link",
+ "post",
+ "star",
+ "voice",
+ "capital",
+ "challenge",
+ "friend",
+ "self",
+ "shot",
+ "brush",
+ "couple",
+ "debate",
+ "exit",
+ "front",
+ "function",
+ "lack",
+ "living",
+ "plant",
+ "plastic",
+ "spot",
+ "summer",
+ "taste",
+ "theme",
+ "track",
+ "wing",
+ "brain",
+ "button",
+ "click",
+ "desire",
+ "foot",
+ "gas",
+ "influence",
+ "notice",
+ "rain",
+ "wall",
+ "base",
+ "damage",
+ "distance",
+ "feeling",
+ "pair",
+ "savings",
+ "staff",
+ "sugar",
+ "target",
+ "text",
+ "animal",
+ "author",
+ "budget",
+ "discount",
+ "file",
+ "ground",
+ "lesson",
+ "minute",
+ "officer",
+ "phase",
+ "reference",
+ "register",
+ "sky",
+ "stage",
+ "stick",
+ "title",
+ "trouble",
+ "bowl",
+ "bridge",
+ "campaign",
+ "character",
+ "club",
+ "edge",
+ "evidence",
+ "fan",
+ "letter",
+ "lock",
+ "maximum",
+ "novel",
+ "option",
+ "pack",
+ "park",
+ "plenty",
+ "quarter",
+ "skin",
+ "sort",
+ "weight",
+ "baby",
+ "background",
+ "carry",
+ "dish",
+ "factor",
+ "fruit",
+ "glass",
+ "joint",
+ "master",
+ "muscle",
+ "red",
+ "strength",
+ "traffic",
+ "trip",
+ "vegetable",
+ "appeal",
+ "chart",
+ "gear",
+ "ideal",
+ "kitchen",
+ "land",
+ "log",
+ "mother",
+ "net",
+ "party",
+ "principle",
+ "relative",
+ "sale",
+ "season",
+ "signal",
+ "spirit",
+ "street",
+ "tree",
+ "wave",
+ "belt",
+ "bench",
+ "commission",
+ "copy",
+ "drop",
+ "minimum",
+ "path",
+ "progress",
+ "project",
+ "sea",
+ "south",
+ "status",
+ "stuff",
+ "ticket",
+ "tour",
+ "angle",
+ "blue",
+ "breakfast",
+ "confidence",
+ "daughter",
+ "degree",
+ "doctor",
+ "dot",
+ "dream",
+ "duty",
+ "essay",
+ "father",
+ "fee",
+ "finance",
+ "hour",
+ "juice",
+ "limit",
+ "luck",
+ "milk",
+ "mouth",
+ "peace",
+ "pipe",
+ "seat",
+ "stable",
+ "storm",
+ "substance",
+ "team",
+ "trick",
+ "afternoon",
+ "bat",
+ "beach",
+ "blank",
+ "catch",
+ "chain",
+ "consideration",
+ "cream",
+ "crew",
+ "detail",
+ "gold",
+ "interview",
+ "kid",
+ "mark",
+ "match",
+ "mission",
+ "pain",
+ "pleasure",
+ "score",
+ "screw",
+ "sex",
+ "shop",
+ "shower",
+ "suit",
+ "tone",
+ "window",
+ "agent",
+ "band",
+ "block",
+ "bone",
+ "calendar",
+ "cap",
+ "coat",
+ "contest",
+ "corner",
+ "court",
+ "cup",
+ "district",
+ "door",
+ "east",
+ "finger",
+ "garage",
+ "guarantee",
+ "hole",
+ "hook",
+ "implement",
+ "layer",
+ "lecture",
+ "lie",
+ "manner",
+ "meeting",
+ "nose",
+ "parking",
+ "partner",
+ "profile",
+ "respect",
+ "rice",
+ "routine",
+ "schedule",
+ "swimming",
+ "telephone",
+ "tip",
+ "winter",
+ "airline",
+ "bag",
+ "battle",
+ "bed",
+ "bill",
+ "bother",
+ "cake",
+ "code",
+ "curve",
+ "designer",
+ "dimension",
+ "dress",
+ "ease",
+ "emergency",
+ "evening",
+ "extension",
+ "farm",
+ "fight",
+ "gap",
+ "grade",
+ "holiday",
+ "horror",
+ "horse",
+ "host",
+ "husband",
+ "loan",
+ "mistake",
+ "mountain",
+ "nail",
+ "noise",
+ "occasion",
+ "package",
+ "patient",
+ "pause",
+ "phrase",
+ "proof",
+ "race",
+ "relief",
+ "sand",
+ "sentence",
+ "shoulder",
+ "smoke",
+ "stomach",
+ "string",
+ "tourist",
+ "towel",
+ "vacation",
+ "west",
+ "wheel",
+ "wine",
+ "arm",
+ "aside",
+ "associate",
+ "bet",
+ "blow",
+ "border",
+ "branch",
+ "breast",
+ "brother",
+ "buddy",
+ "bunch",
+ "chip",
+ "coach",
+ "cross",
+ "document",
+ "draft",
+ "dust",
+ "expert",
+ "floor",
+ "god",
+ "golf",
+ "habit",
+ "iron",
+ "judge",
+ "knife",
+ "landscape",
+ "league",
+ "mail",
+ "mess",
+ "native",
+ "opening",
+ "parent",
+ "pattern",
+ "pin",
+ "pool",
+ "pound",
+ "request",
+ "salary",
+ "shame",
+ "shelter",
+ "shoe",
+ "silver",
+ "tackle",
+ "tank",
+ "trust",
+ "assist",
+ "bake",
+ "bar",
+ "bell",
+ "bike",
+ "blame",
+ "boy",
+ "brick",
+ "chair",
+ "closet",
+ "clue",
+ "collar",
+ "comment",
+ "conference",
+ "devil",
+ "diet",
+ "fear",
+ "fuel",
+ "glove",
+ "jacket",
+ "lunch",
+ "monitor",
+ "mortgage",
+ "nurse",
+ "pace",
+ "panic",
+ "peak",
+ "plane",
+ "reward",
+ "row",
+ "sandwich",
+ "shock",
+ "spite",
+ "spray",
+ "surprise",
+ "till",
+ "transition",
+ "weekend",
+ "welcome",
+ "yard",
+ "alarm",
+ "bend",
+ "bicycle",
+ "bite",
+ "blind",
+ "bottle",
+ "cable",
+ "candle",
+ "clerk",
+ "cloud",
+ "concert",
+ "counter",
+ "flower",
+ "grandfather",
+ "harm",
+ "knee",
+ "lawyer",
+ "leather",
+ "load",
+ "mirror",
+ "neck",
+ "pension",
+ "plate",
+ "purple",
+ "ruin",
+ "ship",
+ "skirt",
+ "slice",
+ "snow",
+ "specialist",
+ "stroke",
+ "switch",
+ "trash",
+ "tune",
+ "zone",
+ "anger",
+ "award",
+ "bid",
+ "bitter",
+ "boot",
+ "bug",
+ "camp",
+ "candy",
+ "carpet",
+ "cat",
+ "champion",
+ "channel",
+ "clock",
+ "comfort",
+ "cow",
+ "crack",
+ "engineer",
+ "entrance",
+ "fault",
+ "grass",
+ "guy",
+ "hell",
+ "highlight",
+ "incident",
+ "island",
+ "joke",
+ "jury",
+ "leg",
+ "lip",
+ "mate",
+ "motor",
+ "nerve",
+ "passage",
+ "pen",
+ "pride",
+ "priest",
+ "prize",
+ "promise",
+ "resident",
+ "resort",
+ "ring",
+ "roof",
+ "rope",
+ "sail",
+ "scheme",
+ "script",
+ "sock",
+ "station",
+ "toe",
+ "tower",
+ "truck",
+ "witness",
+ "a",
+ "you",
+ "it",
+ "can",
+ "will",
+ "if",
+ "one",
+ "many",
+ "most",
+ "other",
+ "use",
+ "make",
+ "good",
+ "look",
+ "help",
+ "go",
+ "great",
+ "being",
+ "few",
+ "might",
+ "still",
+ "public",
+ "read",
+ "keep",
+ "start",
+ "give",
+ "human",
+ "local",
+ "general",
+ "she",
+ "specific",
+ "long",
+ "play",
+ "feel",
+ "high",
+ "tonight",
+ "put",
+ "common",
+ "set",
+ "change",
+ "simple",
+ "past",
+ "big",
+ "possible",
+ "particular",
+ "today",
+ "major",
+ "personal",
+ "current",
+ "national",
+ "cut",
+ "natural",
+ "physical",
+ "show",
+ "try",
+ "check",
+ "second",
+ "call",
+ "move",
+ "pay",
+ "let",
+ "increase",
+ "single",
+ "individual",
+ "turn",
+ "ask",
+ "buy",
+ "guard",
+ "hold",
+ "main",
+ "offer",
+ "potential",
+ "professional",
+ "international",
+ "travel",
+ "cook",
+ "alternative",
+ "following",
+ "special",
+ "working",
+ "whole",
+ "dance",
+ "excuse",
+ "cold",
+ "commercial",
+ "low",
+ "purchase",
+ "deal",
+ "primary",
+ "worth",
+ "fall",
+ "necessary",
+ "positive",
+ "produce",
+ "search",
+ "present",
+ "spend",
+ "talk",
+ "creative",
+ "tell",
+ "cost",
+ "drive",
+ "green",
+ "support",
+ "glad",
+ "remove",
+ "return",
+ "run",
+ "complex",
+ "due",
+ "effective",
+ "middle",
+ "regular",
+ "reserve",
+ "independent",
+ "leave",
+ "original",
+ "reach",
+ "rest",
+ "serve",
+ "watch",
+ "beautiful",
+ "charge",
+ "active",
+ "break",
+ "negative",
+ "safe",
+ "stay",
+ "visit",
+ "visual",
+ "affect",
+ "cover",
+ "report",
+ "rise",
+ "walk",
+ "white",
+ "beyond",
+ "junior",
+ "pick",
+ "unique",
+ "anything",
+ "classic",
+ "final",
+ "lift",
+ "mix",
+ "private",
+ "stop",
+ "teach",
+ "western",
+ "concern",
+ "familiar",
+ "fly",
+ "official",
+ "broad",
+ "comfortable",
+ "gain",
+ "maybe",
+ "rich",
+ "save",
+ "stand",
+ "young",
+ "fail",
+ "heavy",
+ "hello",
+ "lead",
+ "listen",
+ "valuable",
+ "worry",
+ "handle",
+ "leading",
+ "meet",
+ "release",
+ "sell",
+ "finish",
+ "normal",
+ "press",
+ "ride",
+ "secret",
+ "spread",
+ "spring",
+ "tough",
+ "wait",
+ "brown",
+ "deep",
+ "display",
+ "flow",
+ "hit",
+ "objective",
+ "shoot",
+ "touch",
+ "cancel",
+ "chemical",
+ "cry",
+ "dump",
+ "extreme",
+ "push",
+ "conflict",
+ "eat",
+ "fill",
+ "formal",
+ "jump",
+ "kick",
+ "opposite",
+ "pass",
+ "pitch",
+ "remote",
+ "total",
+ "treat",
+ "vast",
+ "abuse",
+ "beat",
+ "burn",
+ "deposit",
+ "print",
+ "raise",
+ "sleep",
+ "somewhere",
+ "advance",
+ "anywhere",
+ "consist",
+ "dark",
+ "double",
+ "draw",
+ "equal",
+ "fix",
+ "hire",
+ "internal",
+ "join",
+ "kill",
+ "sensitive",
+ "tap",
+ "win",
+ "attack",
+ "claim",
+ "constant",
+ "drag",
+ "drink",
+ "guess",
+ "minor",
+ "pull",
+ "raw",
+ "soft",
+ "solid",
+ "wear",
+ "weird",
+ "wonder",
+ "annual",
+ "count",
+ "dead",
+ "doubt",
+ "feed",
+ "forever",
+ "impress",
+ "nobody",
+ "repeat",
+ "round",
+ "sing",
+ "slide",
+ "strip",
+ "whereas",
+ "wish",
+ "combine",
+ "command",
+ "dig",
+ "divide",
+ "equivalent",
+ "hang",
+ "hunt",
+ "initial",
+ "march",
+ "mention",
+ "smell",
+ "spiritual",
+ "survey",
+ "tie",
+ "adult",
+ "brief",
+ "crazy",
+ "escape",
+ "gather",
+ "hate",
+ "prior",
+ "repair",
+ "rough",
+ "sad",
+ "scratch",
+ "sick",
+ "strike",
+ "employ",
+ "external",
+ "hurt",
+ "illegal",
+ "laugh",
+ "lay",
+ "mobile",
+ "nasty",
+ "ordinary",
+ "respond",
+ "royal",
+ "senior",
+ "split",
+ "strain",
+ "struggle",
+ "swim",
+ "train",
+ "upper",
+ "wash",
+ "yellow",
+ "convert",
+ "crash",
+ "dependent",
+ "fold",
+ "funny",
+ "grab",
+ "hide",
+ "miss",
+ "permit",
+ "quote",
+ "recover",
+ "resolve",
+ "roll",
+ "sink",
+ "slip",
+ "spare",
+ "suspect",
+ "sweet",
+ "swing",
+ "twist",
+ "upstairs",
+ "usual",
+ "abroad",
+ "brave",
+ "calm",
+ "concentrate",
+ "estimate",
+ "grand",
+ "male",
+ "mine",
+ "prompt",
+ "quiet",
+ "refuse",
+ "regret",
+ "reveal",
+ "rush",
+ "shake",
+ "shift",
+ "shine",
+ "steal",
+ "suck",
+ "surround",
+ "anybody",
+ "bear",
+ "brilliant",
+ "dare",
+ "dear",
+ "delay",
+ "drunk",
+ "female",
+ "hurry",
+ "inevitable",
+ "invite",
+ "kiss",
+ "neat",
+ "pop",
+ "punch",
+ "quit",
+ "reply",
+ "representative",
+ "resist",
+ "rip",
+ "rub",
+ "silly",
+ "smile",
+ "spell",
+ "stretch",
+ "stupid",
+ "tear",
+ "temporary",
+ "tomorrow",
+ "wake",
+ "wrap",
+ "yesterday"
+];
+var adj = [
+ "abandoned",
+ "able",
+ "absolute",
+ "adorable",
+ "adventurous",
+ "academic",
+ "acceptable",
+ "acclaimed",
+ "accomplished",
+ "accurate",
+ "aching",
+ "acidic",
+ "acrobatic",
+ "active",
+ "actual",
+ "adept",
+ "admirable",
+ "admired",
+ "adolescent",
+ "adorable",
+ "adored",
+ "advanced",
+ "afraid",
+ "affectionate",
+ "aged",
+ "aggravating",
+ "aggressive",
+ "agile",
+ "agitated",
+ "agonizing",
+ "agreeable",
+ "ajar",
+ "alarmed",
+ "alarming",
+ "alert",
+ "alienated",
+ "alive",
+ "all",
+ "altruistic",
+ "amazing",
+ "ambitious",
+ "ample",
+ "amused",
+ "amusing",
+ "anchored",
+ "ancient",
+ "angelic",
+ "angry",
+ "anguished",
+ "animated",
+ "annual",
+ "another",
+ "antique",
+ "anxious",
+ "any",
+ "apprehensive",
+ "appropriate",
+ "apt",
+ "arctic",
+ "arid",
+ "aromatic",
+ "artistic",
+ "ashamed",
+ "assured",
+ "astonishing",
+ "athletic",
+ "attached",
+ "attentive",
+ "attractive",
+ "austere",
+ "authentic",
+ "authorized",
+ "automatic",
+ "avaricious",
+ "average",
+ "aware",
+ "awesome",
+ "awful",
+ "awkward",
+ "babyish",
+ "bad",
+ "back",
+ "baggy",
+ "bare",
+ "barren",
+ "basic",
+ "beautiful",
+ "belated",
+ "beloved",
+ "beneficial",
+ "better",
+ "best",
+ "bewitched",
+ "big",
+ "big-hearted",
+ "biodegradable",
+ "bite-sized",
+ "bitter",
+ "black",
+ "black-and-white",
+ "bland",
+ "blank",
+ "blaring",
+ "bleak",
+ "blind",
+ "blissful",
+ "blond",
+ "blue",
+ "blushing",
+ "bogus",
+ "boiling",
+ "bold",
+ "bony",
+ "boring",
+ "bossy",
+ "both",
+ "bouncy",
+ "bountiful",
+ "bowed",
+ "brave",
+ "breakable",
+ "brief",
+ "bright",
+ "brilliant",
+ "brisk",
+ "broken",
+ "bronze",
+ "brown",
+ "bruised",
+ "bubbly",
+ "bulky",
+ "bumpy",
+ "buoyant",
+ "burdensome",
+ "burly",
+ "bustling",
+ "busy",
+ "buttery",
+ "buzzing",
+ "calculating",
+ "calm",
+ "candid",
+ "canine",
+ "capital",
+ "carefree",
+ "careful",
+ "careless",
+ "caring",
+ "cautious",
+ "cavernous",
+ "celebrated",
+ "charming",
+ "cheap",
+ "cheerful",
+ "cheery",
+ "chief",
+ "chilly",
+ "chubby",
+ "circular",
+ "classic",
+ "clean",
+ "clear",
+ "clear-cut",
+ "clever",
+ "close",
+ "closed",
+ "cloudy",
+ "clueless",
+ "clumsy",
+ "cluttered",
+ "coarse",
+ "cold",
+ "colorful",
+ "colorless",
+ "colossal",
+ "comfortable",
+ "common",
+ "compassionate",
+ "competent",
+ "complete",
+ "complex",
+ "complicated",
+ "composed",
+ "concerned",
+ "concrete",
+ "confused",
+ "conscious",
+ "considerate",
+ "constant",
+ "content",
+ "conventional",
+ "cooked",
+ "cool",
+ "cooperative",
+ "coordinated",
+ "corny",
+ "corrupt",
+ "costly",
+ "courageous",
+ "courteous",
+ "crafty",
+ "crazy",
+ "creamy",
+ "creative",
+ "creepy",
+ "criminal",
+ "crisp",
+ "critical",
+ "crooked",
+ "crowded",
+ "cruel",
+ "crushing",
+ "cuddly",
+ "cultivated",
+ "cultured",
+ "cumbersome",
+ "curly",
+ "curvy",
+ "cute",
+ "cylindrical",
+ "damaged",
+ "damp",
+ "dangerous",
+ "dapper",
+ "daring",
+ "darling",
+ "dark",
+ "dazzling",
+ "dead",
+ "deadly",
+ "deafening",
+ "dear",
+ "dearest",
+ "decent",
+ "decimal",
+ "decisive",
+ "deep",
+ "defenseless",
+ "defensive",
+ "defiant",
+ "deficient",
+ "definite",
+ "definitive",
+ "delayed",
+ "delectable",
+ "delicious",
+ "delightful",
+ "delirious",
+ "demanding",
+ "dense",
+ "dental",
+ "dependable",
+ "dependent",
+ "descriptive",
+ "deserted",
+ "detailed",
+ "determined",
+ "devoted",
+ "different",
+ "difficult",
+ "digital",
+ "diligent",
+ "dim",
+ "dimpled",
+ "dimwitted",
+ "direct",
+ "disastrous",
+ "discrete",
+ "disfigured",
+ "disgusting",
+ "disloyal",
+ "dismal",
+ "distant",
+ "downright",
+ "dreary",
+ "dirty",
+ "disguised",
+ "dishonest",
+ "dismal",
+ "distant",
+ "distinct",
+ "distorted",
+ "dizzy",
+ "dopey",
+ "doting",
+ "double",
+ "downright",
+ "drab",
+ "drafty",
+ "dramatic",
+ "dreary",
+ "droopy",
+ "dry",
+ "dual",
+ "dull",
+ "dutiful",
+ "each",
+ "eager",
+ "earnest",
+ "early",
+ "easy",
+ "easy-going",
+ "ecstatic",
+ "edible",
+ "educated",
+ "elaborate",
+ "elastic",
+ "elated",
+ "elderly",
+ "electric",
+ "elegant",
+ "elementary",
+ "elliptical",
+ "embarrassed",
+ "embellished",
+ "eminent",
+ "emotional",
+ "empty",
+ "enchanted",
+ "enchanting",
+ "energetic",
+ "enlightened",
+ "enormous",
+ "enraged",
+ "entire",
+ "envious",
+ "equal",
+ "equatorial",
+ "essential",
+ "esteemed",
+ "ethical",
+ "euphoric",
+ "even",
+ "evergreen",
+ "everlasting",
+ "every",
+ "evil",
+ "exalted",
+ "excellent",
+ "exemplary",
+ "exhausted",
+ "excitable",
+ "excited",
+ "exciting",
+ "exotic",
+ "expensive",
+ "experienced",
+ "expert",
+ "extraneous",
+ "extroverted",
+ "extra-large",
+ "extra-small",
+ "fabulous",
+ "failing",
+ "faint",
+ "fair",
+ "faithful",
+ "fake",
+ "false",
+ "familiar",
+ "famous",
+ "fancy",
+ "fantastic",
+ "far",
+ "faraway",
+ "far-flung",
+ "far-off",
+ "fast",
+ "fat",
+ "fatal",
+ "fatherly",
+ "favorable",
+ "favorite",
+ "fearful",
+ "fearless",
+ "feisty",
+ "feline",
+ "female",
+ "feminine",
+ "few",
+ "fickle",
+ "filthy",
+ "fine",
+ "finished",
+ "firm",
+ "first",
+ "firsthand",
+ "fitting",
+ "fixed",
+ "flaky",
+ "flamboyant",
+ "flashy",
+ "flat",
+ "flawed",
+ "flawless",
+ "flickering",
+ "flimsy",
+ "flippant",
+ "flowery",
+ "fluffy",
+ "fluid",
+ "flustered",
+ "focused",
+ "fond",
+ "foolhardy",
+ "foolish",
+ "forceful",
+ "forked",
+ "formal",
+ "forsaken",
+ "forthright",
+ "fortunate",
+ "fragrant",
+ "frail",
+ "frank",
+ "frayed",
+ "free",
+ "French",
+ "fresh",
+ "frequent",
+ "friendly",
+ "frightened",
+ "frightening",
+ "frigid",
+ "frilly",
+ "frizzy",
+ "frivolous",
+ "front",
+ "frosty",
+ "frozen",
+ "frugal",
+ "fruitful",
+ "full",
+ "fumbling",
+ "functional",
+ "funny",
+ "fussy",
+ "fuzzy",
+ "gargantuan",
+ "gaseous",
+ "general",
+ "generous",
+ "gentle",
+ "genuine",
+ "giant",
+ "giddy",
+ "gigantic",
+ "gifted",
+ "giving",
+ "glamorous",
+ "glaring",
+ "glass",
+ "gleaming",
+ "gleeful",
+ "glistening",
+ "glittering",
+ "gloomy",
+ "glorious",
+ "glossy",
+ "glum",
+ "golden",
+ "good",
+ "good-natured",
+ "gorgeous",
+ "graceful",
+ "gracious",
+ "grand",
+ "grandiose",
+ "granular",
+ "grateful",
+ "grave",
+ "gray",
+ "great",
+ "greedy",
+ "green",
+ "gregarious",
+ "grim",
+ "grimy",
+ "gripping",
+ "grizzled",
+ "gross",
+ "grotesque",
+ "grouchy",
+ "grounded",
+ "growing",
+ "growling",
+ "grown",
+ "grubby",
+ "gruesome",
+ "grumpy",
+ "guilty",
+ "gullible",
+ "gummy",
+ "hairy",
+ "half",
+ "handmade",
+ "handsome",
+ "handy",
+ "happy",
+ "happy-go-lucky",
+ "hard",
+ "hard-to-find",
+ "harmful",
+ "harmless",
+ "harmonious",
+ "harsh",
+ "hasty",
+ "hateful",
+ "haunting",
+ "healthy",
+ "heartfelt",
+ "hearty",
+ "heavenly",
+ "heavy",
+ "hefty",
+ "helpful",
+ "helpless",
+ "hidden",
+ "hideous",
+ "high",
+ "high-level",
+ "hilarious",
+ "hoarse",
+ "hollow",
+ "homely",
+ "honest",
+ "honorable",
+ "honored",
+ "hopeful",
+ "horrible",
+ "hospitable",
+ "hot",
+ "huge",
+ "humble",
+ "humiliating",
+ "humming",
+ "humongous",
+ "hungry",
+ "hurtful",
+ "husky",
+ "icky",
+ "icy",
+ "ideal",
+ "idealistic",
+ "identical",
+ "idle",
+ "idiotic",
+ "idolized",
+ "ignorant",
+ "ill",
+ "illegal",
+ "ill-fated",
+ "ill-informed",
+ "illiterate",
+ "illustrious",
+ "imaginary",
+ "imaginative",
+ "immaculate",
+ "immaterial",
+ "immediate",
+ "immense",
+ "impassioned",
+ "impeccable",
+ "impartial",
+ "imperfect",
+ "imperturbable",
+ "impish",
+ "impolite",
+ "important",
+ "impossible",
+ "impractical",
+ "impressionable",
+ "impressive",
+ "improbable",
+ "impure",
+ "inborn",
+ "incomparable",
+ "incompatible",
+ "incomplete",
+ "inconsequential",
+ "incredible",
+ "indelible",
+ "inexperienced",
+ "indolent",
+ "infamous",
+ "infantile",
+ "infatuated",
+ "inferior",
+ "infinite",
+ "informal",
+ "innocent",
+ "insecure",
+ "insidious",
+ "insignificant",
+ "insistent",
+ "instructive",
+ "insubstantial",
+ "intelligent",
+ "intent",
+ "intentional",
+ "interesting",
+ "internal",
+ "international",
+ "intrepid",
+ "ironclad",
+ "irresponsible",
+ "irritating",
+ "itchy",
+ "jaded",
+ "jagged",
+ "jam-packed",
+ "jaunty",
+ "jealous",
+ "jittery",
+ "joint",
+ "jolly",
+ "jovial",
+ "joyful",
+ "joyous",
+ "jubilant",
+ "judicious",
+ "juicy",
+ "jumbo",
+ "junior",
+ "jumpy",
+ "juvenile",
+ "kaleidoscopic",
+ "keen",
+ "key",
+ "kind",
+ "kindhearted",
+ "kindly",
+ "klutzy",
+ "knobby",
+ "knotty",
+ "knowledgeable",
+ "knowing",
+ "known",
+ "kooky",
+ "kosher",
+ "lame",
+ "lanky",
+ "large",
+ "last",
+ "lasting",
+ "late",
+ "lavish",
+ "lawful",
+ "lazy",
+ "leading",
+ "lean",
+ "leafy",
+ "left",
+ "legal",
+ "legitimate",
+ "light",
+ "lighthearted",
+ "likable",
+ "likely",
+ "limited",
+ "limp",
+ "limping",
+ "linear",
+ "lined",
+ "liquid",
+ "little",
+ "live",
+ "lively",
+ "livid",
+ "loathsome",
+ "lone",
+ "lonely",
+ "long",
+ "long-term",
+ "loose",
+ "lopsided",
+ "lost",
+ "loud",
+ "lovable",
+ "lovely",
+ "loving",
+ "low",
+ "loyal",
+ "lucky",
+ "lumbering",
+ "luminous",
+ "lumpy",
+ "lustrous",
+ "luxurious",
+ "mad",
+ "made-up",
+ "magnificent",
+ "majestic",
+ "major",
+ "male",
+ "mammoth",
+ "married",
+ "marvelous",
+ "masculine",
+ "massive",
+ "mature",
+ "meager",
+ "mealy",
+ "mean",
+ "measly",
+ "meaty",
+ "medical",
+ "mediocre",
+ "medium",
+ "meek",
+ "mellow",
+ "melodic",
+ "memorable",
+ "menacing",
+ "merry",
+ "messy",
+ "metallic",
+ "mild",
+ "milky",
+ "mindless",
+ "miniature",
+ "minor",
+ "minty",
+ "miserable",
+ "miserly",
+ "misguided",
+ "misty",
+ "mixed",
+ "modern",
+ "modest",
+ "moist",
+ "monstrous",
+ "monthly",
+ "monumental",
+ "moral",
+ "mortified",
+ "motherly",
+ "motionless",
+ "mountainous",
+ "muddy",
+ "muffled",
+ "multicolored",
+ "mundane",
+ "murky",
+ "mushy",
+ "musty",
+ "muted",
+ "mysterious",
+ "naive",
+ "narrow",
+ "nasty",
+ "natural",
+ "naughty",
+ "nautical",
+ "near",
+ "neat",
+ "necessary",
+ "needy",
+ "negative",
+ "neglected",
+ "negligible",
+ "neighboring",
+ "nervous",
+ "new",
+ "next",
+ "nice",
+ "nifty",
+ "nimble",
+ "nippy",
+ "nocturnal",
+ "noisy",
+ "nonstop",
+ "normal",
+ "notable",
+ "noted",
+ "noteworthy",
+ "novel",
+ "noxious",
+ "numb",
+ "nutritious",
+ "nutty",
+ "obedient",
+ "obese",
+ "oblong",
+ "oily",
+ "oblong",
+ "obvious",
+ "occasional",
+ "odd",
+ "oddball",
+ "offbeat",
+ "offensive",
+ "official",
+ "old",
+ "old-fashioned",
+ "only",
+ "open",
+ "optimal",
+ "optimistic",
+ "opulent",
+ "orange",
+ "orderly",
+ "organic",
+ "ornate",
+ "ornery",
+ "ordinary",
+ "original",
+ "other",
+ "our",
+ "outlying",
+ "outgoing",
+ "outlandish",
+ "outrageous",
+ "outstanding",
+ "oval",
+ "overcooked",
+ "overdue",
+ "overjoyed",
+ "overlooked",
+ "palatable",
+ "pale",
+ "paltry",
+ "parallel",
+ "parched",
+ "partial",
+ "passionate",
+ "past",
+ "pastel",
+ "peaceful",
+ "peppery",
+ "perfect",
+ "perfumed",
+ "periodic",
+ "perky",
+ "personal",
+ "pertinent",
+ "pesky",
+ "pessimistic",
+ "petty",
+ "phony",
+ "physical",
+ "piercing",
+ "pink",
+ "pitiful",
+ "plain",
+ "plaintive",
+ "plastic",
+ "playful",
+ "pleasant",
+ "pleased",
+ "pleasing",
+ "plump",
+ "plush",
+ "polished",
+ "polite",
+ "political",
+ "pointed",
+ "pointless",
+ "poised",
+ "poor",
+ "popular",
+ "portly",
+ "posh",
+ "positive",
+ "possible",
+ "potable",
+ "powerful",
+ "powerless",
+ "practical",
+ "precious",
+ "present",
+ "prestigious",
+ "pretty",
+ "precious",
+ "previous",
+ "pricey",
+ "prickly",
+ "primary",
+ "prime",
+ "pristine",
+ "private",
+ "prize",
+ "probable",
+ "productive",
+ "profitable",
+ "profuse",
+ "proper",
+ "proud",
+ "prudent",
+ "punctual",
+ "pungent",
+ "puny",
+ "pure",
+ "purple",
+ "pushy",
+ "putrid",
+ "puzzled",
+ "puzzling",
+ "quaint",
+ "qualified",
+ "quarrelsome",
+ "quarterly",
+ "queasy",
+ "querulous",
+ "questionable",
+ "quick",
+ "quick-witted",
+ "quiet",
+ "quintessential",
+ "quirky",
+ "quixotic",
+ "quizzical",
+ "radiant",
+ "ragged",
+ "rapid",
+ "rare",
+ "rash",
+ "raw",
+ "recent",
+ "reckless",
+ "rectangular",
+ "ready",
+ "real",
+ "realistic",
+ "reasonable",
+ "red",
+ "reflecting",
+ "regal",
+ "regular",
+ "reliable",
+ "relieved",
+ "remarkable",
+ "remorseful",
+ "remote",
+ "repentant",
+ "required",
+ "respectful",
+ "responsible",
+ "repulsive",
+ "revolving",
+ "rewarding",
+ "rich",
+ "rigid",
+ "right",
+ "ringed",
+ "ripe",
+ "roasted",
+ "robust",
+ "rosy",
+ "rotating",
+ "rotten",
+ "rough",
+ "round",
+ "rowdy",
+ "royal",
+ "rubbery",
+ "rundown",
+ "ruddy",
+ "rude",
+ "runny",
+ "rural",
+ "rusty",
+ "sad",
+ "safe",
+ "salty",
+ "same",
+ "sandy",
+ "sane",
+ "sarcastic",
+ "sardonic",
+ "satisfied",
+ "scaly",
+ "scarce",
+ "scared",
+ "scary",
+ "scented",
+ "scholarly",
+ "scientific",
+ "scornful",
+ "scratchy",
+ "scrawny",
+ "second",
+ "secondary",
+ "second-hand",
+ "secret",
+ "self-assured",
+ "self-reliant",
+ "selfish",
+ "sentimental",
+ "separate",
+ "serene",
+ "serious",
+ "serpentine",
+ "several",
+ "severe",
+ "shabby",
+ "shadowy",
+ "shady",
+ "shallow",
+ "shameful",
+ "shameless",
+ "sharp",
+ "shimmering",
+ "shiny",
+ "shocked",
+ "shocking",
+ "shoddy",
+ "short",
+ "short-term",
+ "showy",
+ "shrill",
+ "shy",
+ "sick",
+ "silent",
+ "silky",
+ "silly",
+ "silver",
+ "similar",
+ "simple",
+ "simplistic",
+ "sinful",
+ "single",
+ "sizzling",
+ "skeletal",
+ "skinny",
+ "sleepy",
+ "slight",
+ "slim",
+ "slimy",
+ "slippery",
+ "slow",
+ "slushy",
+ "small",
+ "smart",
+ "smoggy",
+ "smooth",
+ "smug",
+ "snappy",
+ "snarling",
+ "sneaky",
+ "sniveling",
+ "snoopy",
+ "sociable",
+ "soft",
+ "soggy",
+ "solid",
+ "somber",
+ "some",
+ "spherical",
+ "sophisticated",
+ "sore",
+ "sorrowful",
+ "soulful",
+ "soupy",
+ "sour",
+ "Spanish",
+ "sparkling",
+ "sparse",
+ "specific",
+ "spectacular",
+ "speedy",
+ "spicy",
+ "spiffy",
+ "spirited",
+ "spiteful",
+ "splendid",
+ "spotless",
+ "spotted",
+ "spry",
+ "square",
+ "squeaky",
+ "squiggly",
+ "stable",
+ "staid",
+ "stained",
+ "stale",
+ "standard",
+ "starchy",
+ "stark",
+ "starry",
+ "steep",
+ "sticky",
+ "stiff",
+ "stimulating",
+ "stingy",
+ "stormy",
+ "straight",
+ "strange",
+ "steel",
+ "strict",
+ "strident",
+ "striking",
+ "striped",
+ "strong",
+ "studious",
+ "stunning",
+ "stupendous",
+ "stupid",
+ "sturdy",
+ "stylish",
+ "subdued",
+ "submissive",
+ "substantial",
+ "subtle",
+ "suburban",
+ "sudden",
+ "sugary",
+ "sunny",
+ "super",
+ "superb",
+ "superficial",
+ "superior",
+ "supportive",
+ "sure-footed",
+ "surprised",
+ "suspicious",
+ "svelte",
+ "sweaty",
+ "sweet",
+ "sweltering",
+ "swift",
+ "sympathetic",
+ "tall",
+ "talkative",
+ "tame",
+ "tan",
+ "tangible",
+ "tart",
+ "tasty",
+ "tattered",
+ "taut",
+ "tedious",
+ "teeming",
+ "tempting",
+ "tender",
+ "tense",
+ "tepid",
+ "terrible",
+ "terrific",
+ "testy",
+ "thankful",
+ "that",
+ "these",
+ "thick",
+ "thin",
+ "third",
+ "thirsty",
+ "this",
+ "thorough",
+ "thorny",
+ "those",
+ "thoughtful",
+ "threadbare",
+ "thrifty",
+ "thunderous",
+ "tidy",
+ "tight",
+ "timely",
+ "tinted",
+ "tiny",
+ "tired",
+ "torn",
+ "total",
+ "tough",
+ "traumatic",
+ "treasured",
+ "tremendous",
+ "tragic",
+ "trained",
+ "tremendous",
+ "triangular",
+ "tricky",
+ "trifling",
+ "trim",
+ "trivial",
+ "troubled",
+ "true",
+ "trusting",
+ "trustworthy",
+ "trusty",
+ "truthful",
+ "tubby",
+ "turbulent",
+ "twin",
+ "ugly",
+ "ultimate",
+ "unacceptable",
+ "unaware",
+ "uncomfortable",
+ "uncommon",
+ "unconscious",
+ "understated",
+ "unequaled",
+ "uneven",
+ "unfinished",
+ "unfit",
+ "unfolded",
+ "unfortunate",
+ "unhappy",
+ "unhealthy",
+ "uniform",
+ "unimportant",
+ "unique",
+ "united",
+ "unkempt",
+ "unknown",
+ "unlawful",
+ "unlined",
+ "unlucky",
+ "unnatural",
+ "unpleasant",
+ "unrealistic",
+ "unripe",
+ "unruly",
+ "unselfish",
+ "unsightly",
+ "unsteady",
+ "unsung",
+ "untidy",
+ "untimely",
+ "untried",
+ "untrue",
+ "unused",
+ "unusual",
+ "unwelcome",
+ "unwieldy",
+ "unwilling",
+ "unwitting",
+ "unwritten",
+ "upbeat",
+ "upright",
+ "upset",
+ "urban",
+ "usable",
+ "used",
+ "useful",
+ "useless",
+ "utilized",
+ "utter",
+ "vacant",
+ "vague",
+ "vain",
+ "valid",
+ "valuable",
+ "vapid",
+ "variable",
+ "vast",
+ "velvety",
+ "venerated",
+ "vengeful",
+ "verifiable",
+ "vibrant",
+ "vicious",
+ "victorious",
+ "vigilant",
+ "vigorous",
+ "villainous",
+ "violet",
+ "violent",
+ "virtual",
+ "virtuous",
+ "visible",
+ "vital",
+ "vivacious",
+ "vivid",
+ "voluminous",
+ "wan",
+ "warlike",
+ "warm",
+ "warmhearted",
+ "warped",
+ "wary",
+ "wasteful",
+ "watchful",
+ "waterlogged",
+ "watery",
+ "wavy",
+ "wealthy",
+ "weak",
+ "weary",
+ "webbed",
+ "weed",
+ "weekly",
+ "weepy",
+ "weighty",
+ "weird",
+ "welcome",
+ "well-documented",
+ "well-groomed",
+ "well-informed",
+ "well-lit",
+ "well-made",
+ "well-off",
+ "well-to-do",
+ "well-worn",
+ "wet",
+ "which",
+ "whimsical",
+ "whirlwind",
+ "whispered",
+ "white",
+ "whole",
+ "whopping",
+ "wicked",
+ "wide",
+ "wide-eyed",
+ "wiggly",
+ "wild",
+ "willing",
+ "wilted",
+ "winding",
+ "windy",
+ "winged",
+ "wiry",
+ "wise",
+ "witty",
+ "wobbly",
+ "woeful",
+ "wonderful",
+ "wooden",
+ "woozy",
+ "wordy",
+ "worldly",
+ "worn",
+ "worried",
+ "worrisome",
+ "worse",
+ "worst",
+ "worthless",
+ "worthwhile",
+ "worthy",
+ "wrathful",
+ "wretched",
+ "writhing",
+ "wrong",
+ "wry",
+ "yawning",
+ "yearly",
+ "yellow",
+ "yellowish",
+ "young",
+ "youthful",
+ "yummy",
+ "zany",
+ "zealous",
+ "zesty",
+ "zigzag"
+];
+function getRandomUsername() {
+ const n2 = Math.floor(Math.random() * noun.length);
+ const a5 = Math.floor(Math.random() * adj.length);
+ return {
+ first: adj[a5],
+ second: noun[n2]
+ };
+}
+function getRandomPassword() {
+ return encodeCrock(getRandomBytes(16));
+}
+
+// src/pages/RegistrationPage.tsx
+function RegistrationPage({
+ onRegistrationSuccesful,
+ routeCancel
+}) {
+ const { i18n: i18n2 } = useTranslationContext();
+ const { config } = useBankCoreApiContext();
+ if (!config.allow_registrations) {
+ return /* @__PURE__ */ h("p", null, i18n2.str`Currently, the bank is not accepting new registrations!`);
+ }
+ return /* @__PURE__ */ h(
+ RegistrationForm,
{
- message: error2,
- isDirty: value !== void 0
+ onRegistrationSuccesful,
+ routeCancel
}
- )), help && /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, help));
+ );
+}
+var USERNAME_REGEX2 = /^[a-zA-Z0-9\-\.\_\~]*$/;
+function RegistrationForm({
+ onRegistrationSuccesful,
+ routeCancel
+}) {
+ const [username, setUsername] = p3();
+ const [name, setName] = p3();
+ const [password, setPassword] = p3();
+ const [repeatPassword, setRepeatPassword] = p3();
+ const [notification, , handleError] = useLocalNotification();
+ const settings = useSettingsContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ const { i18n: i18n2 } = useTranslationContext();
+ const errors2 = undefinedIfEmpty({
+ name: !name ? i18n2.str`Missing name` : void 0,
+ username: !username ? i18n2.str`Missing username` : !USERNAME_REGEX2.test(username) ? i18n2.str`Use letters, numbers or any of these characters: - . _ ~` : void 0,
+ // phone: !phone
+ // ? undefined
+ // : !PHONE_REGEX.test(phone)
+ // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
+ // : undefined,
+ // email: !email
+ // ? undefined
+ // : !EMAIL_REGEX.test(email)
+ // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
+ // : undefined,
+ password: !password ? i18n2.str`Missing password` : void 0,
+ repeatPassword: !repeatPassword ? i18n2.str`Missing password` : repeatPassword !== password ? i18n2.str`Passwords don't match` : void 0
+ });
+ async function doRegistrationAndLogin(name2, username2, password2, onComplete) {
+ await handleError(async (onError) => {
+ const resp = await api.createAccount("", {
+ name: name2,
+ username: username2,
+ password: password2
+ });
+ if (resp.type === "ok") {
+ onComplete();
+ } else {
+ onError(resp, (_case) => {
+ switch (_case) {
+ case HttpStatusCode.BadRequest:
+ return i18n2.str`Server replied with invalid phone or email.`;
+ case HttpStatusCode.Unauthorized:
+ return i18n2.str`No enough permission to create that account.`;
+ case TalerErrorCode.BANK_UNALLOWED_DEBIT:
+ return i18n2.str`Registration is disabled because the bank ran out of bonus credit.`;
+ case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
+ return i18n2.str`That username can't be used because is reserved.`;
+ case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
+ return i18n2.str`That username is already taken.`;
+ case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
+ return i18n2.str`That account id is already taken.`;
+ case TalerErrorCode.BANK_MISSING_TAN_INFO:
+ return i18n2.str`No information for the selected authentication channel.`;
+ case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
+ return i18n2.str`Authentication channel is not supported.`;
+ case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
+ return i18n2.str`Only admin is allow to set debt limit.`;
+ case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
+ return i18n2.str`Only admin can create accounts with second factor authentication.`;
+ }
+ });
+ }
+ });
+ }
+ async function doRegistrationStep() {
+ if (!username || !password || !name)
+ return;
+ await doRegistrationAndLogin(name, username, password, () => {
+ setUsername(void 0);
+ setPassword(void 0);
+ setRepeatPassword(void 0);
+ onRegistrationSuccesful(username, password);
+ });
+ }
+ async function doRandomRegistration() {
+ const user = getRandomUsername();
+ const password2 = settings.simplePasswordForRandomAccounts ? "123" : getRandomPassword();
+ const username2 = `_${user.first}-${user.second}_`;
+ const name2 = `${capitalizeFirstLetter(user.first)} ${capitalizeFirstLetter(
+ user.second
+ )}`;
+ await doRegistrationAndLogin(name2, username2, password2, () => {
+ onRegistrationSuccesful(username2, password2);
+ });
+ }
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "flex min-h-full flex-col justify-center" }, /* @__PURE__ */ h("div", { class: "sm:mx-auto sm:w-full sm:max-w-sm" }, /* @__PURE__ */ h("h2", { class: "text-center text-2xl font-bold leading-9 tracking-tight text-gray-900" }, i18n2.str`Account registration`)), /* @__PURE__ */ h("div", { class: "mt-10 sm:mx-auto sm:w-full sm:max-w-sm" }, /* @__PURE__ */ h(
+ "form",
+ {
+ class: "space-y-6",
+ noValidate: true,
+ onSubmit: (e4) => {
+ e4.preventDefault();
+ },
+ autoCapitalize: "none",
+ autoCorrect: "off"
+ },
+ /* @__PURE__ */ h("div", null, /* @__PURE__ */ h(
+ "label",
+ {
+ for: "username",
+ class: "block text-sm font-medium leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Login username"),
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ autoFocus: true,
+ type: "text",
+ name: "username",
+ id: "username",
+ class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ value: username ?? "",
+ enterkeyhint: "next",
+ placeholder: "account identification to login",
+ autocomplete: "username",
+ required: true,
+ onInput: (e4) => {
+ setUsername(e4.currentTarget.value);
+ }
+ }
+ ), /* @__PURE__ */ h(
+ ShowInputErrorLabel,
+ {
+ message: errors2?.username,
+ isDirty: username !== void 0
+ }
+ ))),
+ /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h(
+ "label",
+ {
+ for: "password",
+ class: "block text-sm font-medium leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Password"),
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
+ )), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "password",
+ name: "password",
+ id: "password",
+ autocomplete: "current-password",
+ class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ enterkeyhint: "send",
+ value: password ?? "",
+ placeholder: "Password",
+ required: true,
+ onInput: (e4) => {
+ setPassword(e4.currentTarget.value);
+ }
+ }
+ ), /* @__PURE__ */ h(
+ ShowInputErrorLabel,
+ {
+ message: errors2?.password,
+ isDirty: password !== void 0
+ }
+ ))),
+ /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h(
+ "label",
+ {
+ for: "register-repeat",
+ class: "block text-sm font-medium leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Repeat password"),
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
+ )), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "password",
+ name: "register-repeat",
+ id: "register-repeat",
+ autocomplete: "current-password",
+ class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ enterkeyhint: "send",
+ value: repeatPassword ?? "",
+ placeholder: "Same password",
+ required: true,
+ onInput: (e4) => {
+ setRepeatPassword(e4.currentTarget.value);
+ }
+ }
+ ), /* @__PURE__ */ h(
+ ShowInputErrorLabel,
+ {
+ message: errors2?.repeatPassword,
+ isDirty: repeatPassword !== void 0
+ }
+ ))),
+ /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h(
+ "label",
+ {
+ for: "name",
+ class: "block text-sm font-medium leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Full name"),
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
+ )), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ autoFocus: true,
+ type: "text",
+ name: "name",
+ id: "name",
+ class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ value: name ?? "",
+ enterkeyhint: "next",
+ placeholder: "John Doe",
+ autocomplete: "name",
+ required: true,
+ onInput: (e4) => {
+ setName(e4.currentTarget.value);
+ }
+ }
+ ))),
+ /* @__PURE__ */ h("div", { class: "flex w-full justify-between" }, /* @__PURE__ */ h(
+ "a",
+ {
+ name: "cancel",
+ href: routeCancel.url({}),
+ class: "ring-1 ring-gray-600 rounded-md bg-white disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-white-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")
+ ), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "submit",
+ name: "register",
+ class: " rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
+ disabled: !!errors2,
+ onClick: async (e4) => {
+ e4.preventDefault();
+ doRegistrationStep();
+ }
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Register")
+ ))
+ ), settings.allowRandomAccountCreation && /* @__PURE__ */ h("p", { class: "mt-10 text-center text-sm text-gray-500 border-t" }, /* @__PURE__ */ h(
+ "button",
+ {
+ type: "submit",
+ name: "create random",
+ class: "flex mt-4 w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600",
+ onClick: (e4) => {
+ e4.preventDefault();
+ doRandomRegistration();
+ }
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Create a random temporary user")
+ )))));
+}
+function capitalizeFirstLetter(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
}
// src/pages/LoginForm.tsx
@@ -25629,14 +28269,14 @@ function LoginForm({
fixedUser,
routeRegister
}) {
- const backend = useBackendState();
- const sessionUser = backend.state.status !== "loggedOut" ? backend.state.username : void 0;
+ const session = useSessionState();
+ const sessionUser = session.state.status !== "loggedOut" ? session.state.username : void 0;
const [username, setUsername] = p3(
currentUser ?? sessionUser
);
const [password, setPassword] = p3();
const { i18n: i18n2 } = useTranslationContext();
- const { api } = useBankCoreApiContext();
+ const { lib: { auth: authenticator } } = useBankCoreApiContext();
const [notification, withErrorHandler] = useLocalNotificationHandler();
const { config } = useBankCoreApiContext();
const ref = _2(null);
@@ -25644,25 +28284,21 @@ function LoginForm({
ref.current?.focus();
}, []);
const errors2 = undefinedIfEmpty({
- username: !username ? i18n2.str`Missing username` : (
- // : !USERNAME_REGEX.test(username)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- void 0
- ),
+ username: !username ? i18n2.str`Missing username` : !USERNAME_REGEX2.test(username) ? i18n2.str`Use letters, numbers or any of these characters: - . _ ~` : void 0,
password: !password ? i18n2.str`Missing password` : void 0
});
async function doLogout() {
- backend.logOut();
+ session.logOut();
}
const loginHandler = !username || !password ? void 0 : withErrorHandler(
- async () => api.getAuthenticationAPI(username).createAccessToken(password, {
+ async () => authenticator(username).createAccessToken(password, {
// scope: "readwrite" as "write", // FIX: different than merchant
scope: "readwrite",
duration: { d_us: "forever" },
refreshable: true
}),
(result) => {
- backend.logIn({ username, token: result.body.access_token });
+ session.logIn({ username, token: result.body.access_token });
},
(fail) => {
switch (fail.case) {
@@ -25748,7 +28384,7 @@ function LoginForm({
isDirty: password !== void 0
}
))),
- backend.state.status !== "loggedOut" ? /* @__PURE__ */ h("div", { class: "flex justify-between" }, /* @__PURE__ */ h(
+ session.state.status !== "loggedOut" ? /* @__PURE__ */ h("div", { class: "flex justify-between" }, /* @__PURE__ */ h(
"button",
{
type: "submit",
@@ -25792,6 +28428,179 @@ function LoginForm({
)));
}
+// src/hooks/account.ts
+init_hooks_module();
+var useSWR2 = useSWR;
+function revalidateAccountDetails() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getAccount",
+ void 0,
+ { revalidate: true }
+ );
+}
+function useAccountDetails(account) {
+ const { state: credentials } = useSessionState();
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ async function fetcher([username, token2]) {
+ return await api.getAccount({ username, token: token2 });
+ }
+ const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
+ const { data, error: error2 } = useSWR2([account, token, "getAccount"], fetcher, {});
+ if (data)
+ return data;
+ if (error2)
+ return error2;
+ return void 0;
+}
+function useWithdrawalDetails(wid) {
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ const [latestStatus, setLatestStatus] = p3();
+ async function fetcher([wid2, old_state]) {
+ return await api.getWithdrawalById(
+ wid2,
+ old_state === void 0 ? void 0 : { old_state, timeoutMs: 15e3 }
+ );
+ }
+ const { data, error: error2 } = useSWR2([wid, latestStatus, "getWithdrawalById"], fetcher, {
+ refreshInterval: 3e3,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
+ });
+ const currentStatus = data !== void 0 && data.type === "ok" ? data.body.status : void 0;
+ h2(() => {
+ if (currentStatus !== void 0 && currentStatus !== latestStatus) {
+ setLatestStatus(currentStatus);
+ }
+ }, [currentStatus]);
+ if (data)
+ return data;
+ if (error2)
+ return error2;
+ return void 0;
+}
+async function revalidatePublicAccounts() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getPublicAccounts",
+ void 0,
+ { revalidate: true }
+ );
+}
+function usePublicAccounts(filterAccount, initial3) {
+ const [offset, setOffset] = p3(initial3);
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ async function fetcher([account, txid]) {
+ return await api.getPublicAccounts(
+ { account },
+ {
+ limit: PAGE_SIZE,
+ offset: txid ? String(txid) : void 0,
+ order: "asc"
+ }
+ );
+ }
+ const { data, error: error2 } = useSWR2([filterAccount, offset, "getPublicAccounts"], fetcher, {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
+ });
+ const isLastPage = data && data.type === "ok" && data.body.public_accounts.length <= PAGE_SIZE;
+ const isFirstPage = !offset;
+ const result = data && data.type == "ok" ? structuredClone(data.body.public_accounts) : [];
+ if (result.length == PAGE_SIZE + 1) {
+ result.pop();
+ }
+ const pagination = {
+ result,
+ isLastPage,
+ isFirstPage,
+ loadNext: () => {
+ if (!result.length)
+ return;
+ setOffset(result[result.length - 1].row_id);
+ },
+ loadFirst: () => {
+ setOffset(0);
+ }
+ };
+ if (data) {
+ return { ok: true, data: data.body, ...pagination };
+ }
+ if (error2) {
+ return error2;
+ }
+ return void 0;
+}
+function revalidateTransactions() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getTransactions",
+ void 0,
+ { revalidate: true }
+ );
+}
+function useTransactions(account, initial3) {
+ const { state: credentials } = useSessionState();
+ const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
+ const [offset, setOffset] = p3(initial3);
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ async function fetcher([username, token2, txid]) {
+ return await api.getTransactions(
+ { username, token: token2 },
+ {
+ limit: PAGE_SIZE + 1,
+ offset: txid ? String(txid) : void 0,
+ order: "dec"
+ }
+ );
+ }
+ const { data, error: error2 } = useSWR2([account, token, offset, "getTransactions"], fetcher, {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ refreshWhenOffline: false,
+ // revalidateOnMount: false,
+ revalidateIfStale: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false
+ });
+ const isLastPage = data && data.type === "ok" && data.body.transactions.length <= PAGE_SIZE;
+ const isFirstPage = !offset;
+ const result = data && data.type == "ok" ? structuredClone(data.body.transactions) : [];
+ if (result.length == PAGE_SIZE + 1) {
+ result.pop();
+ }
+ const pagination = {
+ result,
+ isLastPage,
+ isFirstPage,
+ loadNext: () => {
+ if (!result.length)
+ return;
+ setOffset(result[result.length - 1].row_id);
+ },
+ loadFirst: () => {
+ setOffset(0);
+ }
+ };
+ if (data) {
+ return { ok: true, data, ...pagination };
+ }
+ if (error2) {
+ return error2;
+ }
+ return void 0;
+}
+
// src/pages/AccountPage/state.ts
function useComponentState({
account,
@@ -25850,6 +28659,7 @@ function useComponentState({
}
const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
const limit = balanceIsDebit ? Amounts.sub(debitThreshold, balance).amount : Amounts.add(balance, debitThreshold).amount;
+ const positiveBalance = balanceIsDebit ? Amounts.zeroOfAmount(balance) : balance;
return {
status: "ready",
onOperationCreated,
@@ -25866,7 +28676,8 @@ function useComponentState({
routeChargeWallet,
routeWireTransfer,
account,
- limit
+ limit,
+ balance: positiveBalance
};
}
@@ -25874,7 +28685,10 @@ function useComponentState({
init_preact_module();
// src/components/Transactions/state.ts
-function useComponentState2({ account, routeCreateWireTransfer }) {
+function useComponentState2({
+ account,
+ routeCreateWireTransfer
+}) {
const txResult = useTransactions(account);
if (!txResult) {
return {
@@ -25893,7 +28707,7 @@ function useComponentState2({ account, routeCreateWireTransfer }) {
const cp = parsePaytoUri(
negative ? tx.creditor_payto_uri : tx.debtor_payto_uri
);
- const counterpart = (cp === void 0 || !cp.isKnown ? void 0 : cp.targetType === "iban" ? cp.iban : cp.targetType === "x-taler-bank" ? cp.account : cp.targetType === "bitcoin" ? `${cp.targetPath.substring(0, 6)}...` : void 0) ?? "unknown";
+ const counterpart = (cp === void 0 || !cp.isKnown ? void 0 : cp.targetType === "iban" ? cp.iban : cp.targetType === "x-taler-bank" ? cp.account : cp.targetType === "bitcoin" ? `${cp.address.substring(0, 6)}...` : void 0) ?? "unknown";
const when = AbsoluteTime.fromProtocolTimestamp(tx.date);
const amount = Amounts.parse(tx.amount);
const subject = tx.subject;
@@ -28090,7 +30904,7 @@ function ReadyView({
},
{}
);
- return /* @__PURE__ */ h("div", { class: "px-4 mt-4" }, /* @__PURE__ */ h("div", { class: "sm:flex sm:items-center" }, /* @__PURE__ */ h("div", { class: "sm:flex-auto" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transactions history")))), /* @__PURE__ */ h("div", { class: "-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white" }, /* @__PURE__ */ h("table", { class: "min-w-full divide-y divide-gray-300" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("div", { class: "px-4 mt-8" }, /* @__PURE__ */ h("div", { class: "sm:flex sm:items-center" }, /* @__PURE__ */ h("div", { class: "sm:flex-auto" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transactions history")))), /* @__PURE__ */ h("div", { class: "-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white" }, /* @__PURE__ */ h("table", { class: "min-w-full divide-y divide-gray-300" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h(
"th",
{
scope: "col",
@@ -28235,6 +31049,7 @@ var Transactions = utils_exports.compose(
// src/pages/PaymentOptions.tsx
init_preact_module();
+init_hooks_module();
// src/pages/WalletWithdrawForm.tsx
init_preact_module();
@@ -28252,16 +31067,16 @@ function useComponentState3({
}) {
const [settings] = usePreferences();
const [bankState, updateBankState] = useBankState();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
- const { api } = useBankCoreApiContext();
+ const { lib: { bank } } = useBankCoreApiContext();
const [failure2, setFailure] = p3();
const amount = settings.maxWithdrawalAmount;
async function doSilentStart() {
const parsedAmount = Amounts.parseOrThrow(`${currency}:${amount}`);
if (!creds)
return;
- const resp = await api.createWithdrawal(creds, {
+ const resp = await bank.createWithdrawal(creds, {
amount: Amounts.stringify(parsedAmount)
});
if (resp.type === "fail") {
@@ -28292,7 +31107,7 @@ function useComponentState3({
async function doAbort() {
if (!creds)
return;
- const resp = await api.abortWithdrawalById(creds, wid);
+ const resp = await bank.abortWithdrawalById(creds, wid);
if (resp.type === "ok") {
onAbort();
} else {
@@ -28302,7 +31117,7 @@ function useComponentState3({
async function doConfirm() {
if (!creds)
return;
- const resp = await api.confirmWithdrawalById(creds, wid);
+ const resp = await bank.confirmWithdrawalById(creds, wid);
if (resp.type === "ok") {
mutate(() => true);
} else {
@@ -28310,7 +31125,7 @@ function useComponentState3({
}
}
const uri = stringifyWithdrawUri({
- bankIntegrationApiBaseUrl: api.getIntegrationAPI().baseUrl,
+ bankIntegrationApiBaseUrl: bank.getIntegrationAPI().href,
withdrawalOperationId
});
const parsedUri = parseWithdrawUri(uri);
@@ -28466,11 +31281,11 @@ function WithdrawalConfirmationQuestion({
}) {
const { i18n: i18n2 } = useTranslationContext();
const [settings] = usePreferences();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
const [, updateBankState] = useBankState();
const [notification, notify2, handleError] = useLocalNotification();
- const { config, api } = useBankCoreApiContext();
+ const { config, lib: { bank: api } } = useBankCoreApiContext();
async function doTransfer() {
await handleError(async () => {
if (!creds)
@@ -28491,41 +31306,48 @@ function WithdrawalConfirmationQuestion({
type: "error",
title: i18n2.str`The withdrawal has been aborted previously and can't be confirmed`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
return notify2({
type: "error",
title: i18n2.str`The withdrawal operation can't be confirmed before a wallet accepted the transaction.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.BadRequest:
return notify2({
type: "error",
title: i18n2.str`The operation id is invalid.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The operation was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return notify2({
type: "error",
title: i18n2.str`Your balance is not enough for the operation.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Accepted: {
updateBankState("currentChallenge", {
operation: "confirm-withdrawal",
id: String(resp.body.challenge_id),
- location: routeHere.url({ wopid: withdrawUri.withdrawalOperationId }),
+ location: routeHere.url({
+ wopid: withdrawUri.withdrawalOperationId
+ }),
sent: AbsoluteTime.never(),
request: withdrawUri.withdrawalOperationId
});
@@ -28552,21 +31374,26 @@ function WithdrawalConfirmationQuestion({
case HttpStatusCode.Conflict:
return notify2({
type: "error",
- title: i18n2.str`The reserve operation has been confirmed previously and can't be aborted`
+ title: i18n2.str`The reserve operation has been confirmed previously and can't be aborted`,
+ description: resp.detail.hint,
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.BadRequest:
return notify2({
type: "error",
title: i18n2.str`The operation id is invalid.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The operation was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
default: {
assertUnreachable(resp);
@@ -28586,19 +31413,25 @@ function WithdrawalConfirmationQuestion({
}
},
/* @__PURE__ */ h("div", { class: "px-4 mt-4" }, /* @__PURE__ */ h("div", { class: "w-full" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0 text-sm" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "Wire transfer details"))), /* @__PURE__ */ h("div", { class: "mt-6 border-t border-gray-100" }, /* @__PURE__ */ h("dl", { class: "divide-y divide-gray-100" }, (() => {
+ if (!details.account.isKnown) {
+ return /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, details.account.targetPath));
+ }
switch (details.account.targetType) {
case "iban": {
- const p4 = details.account;
- const name = p4.params["receiver-name"];
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account number")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, p4.iban)), name && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's name")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, name)));
+ const name = details.account.params["receiver-name"];
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account number")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, details.account.iban)), name && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's name")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, name)));
}
case "x-taler-bank": {
- const p4 = details.account;
- const name = p4.params["receiver-name"];
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account id")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, p4.account)), name && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's name")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, name)));
+ const name = details.account.params["receiver-name"];
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account bank hostname")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, details.account.host)), /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account id")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, details.account.account)), name && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's name")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, name)));
+ }
+ case "bitcoin": {
+ const name = details.account.params["receiver-name"];
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account address")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, details.account.address)), name && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's name")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, name)));
+ }
+ default: {
+ assertUnreachable(details.account);
}
- default:
- return /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment provider's account")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, details.account.targetPath));
}
})(), /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Amount")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, /* @__PURE__ */ h(
RenderAmount,
@@ -28635,7 +31468,7 @@ function ShouldBeSameUser({
username,
children
}) {
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const { i18n: i18n2 } = useTranslationContext();
if (credentials.status === "loggedOut") {
return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(Attention, { type: "info", title: i18n2.str`Authentication required` }), /* @__PURE__ */ h(LoginForm, { currentUser: username, fixedUser: true }));
@@ -28652,38 +31485,6 @@ function ShouldBeSameUser({
return /* @__PURE__ */ h(p2, null, children);
}
-// src/context/wallet-integration.ts
-init_preact_module();
-init_hooks_module();
-function createHeadMetaTag(uri, onNotFound) {
- const meta = document.createElement("meta");
- meta.setAttribute("name", "taler-uri");
- meta.setAttribute("content", stringifyTalerUri(uri));
- document.head.appendChild(meta);
- let walletFound = false;
- window.addEventListener("beforeunload", () => {
- walletFound = true;
- });
- setTimeout(() => {
- if (!walletFound && onNotFound) {
- onNotFound();
- }
- }, 10);
-}
-var Context5 = B(void 0);
-var useTalerWalletIntegrationAPI = () => q2(Context5);
-var TalerWalletIntegrationBrowserProvider = ({
- children
-}) => {
- const value = {
- publishTalerAction: createHeadMetaTag
- };
- return h(Context5.Provider, {
- value,
- children
- });
-};
-
// src/pages/OperationState/views.tsx
function InvalidPaytoView({ payto }) {
return /* @__PURE__ */ h("div", null, 'Payto from server is not valid "', payto, '"');
@@ -28719,21 +31520,24 @@ function NeedConfirmationView({
type: "error",
title: i18n2.str`The reserve operation has been confirmed previously and can't be aborted`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.BadRequest:
return notify2({
type: "error",
title: i18n2.str`The operation id is invalid.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The operation was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
default:
assertUnreachable(resp);
@@ -28757,35 +31561,40 @@ function NeedConfirmationView({
type: "error",
title: i18n2.str`The withdrawal has been aborted previously and can't be confirmed`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
return notify2({
type: "error",
title: i18n2.str`The withdrawal operation can't be confirmed before a wallet accepted the transaction.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.BadRequest:
return notify2({
type: "error",
title: i18n2.str`The operation id is invalid.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The operation was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return notify2({
type: "error",
title: i18n2.str`Your balance is not enough.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Accepted: {
updateBankState("currentChallenge", {
@@ -28948,10 +31757,7 @@ function ConfirmedView({ routeClose }) {
/* @__PURE__ */ h(i18n2.Translate, null, "Close")
)));
}
-function ReadyView2({
- uri,
- onAbort: doAbort
-}) {
+function ReadyView2({ uri, onAbort: doAbort }) {
const { i18n: i18n2 } = useTranslationContext();
const walletInegrationApi = useTalerWalletIntegrationAPI();
const [notification, notify2, errorHandler] = useLocalNotification();
@@ -28970,21 +31776,24 @@ function ReadyView2({
type: "error",
title: i18n2.str`The reserve operation has been confirmed previously and can't be aborted`,
description: hasError.detail.hint,
- debug: hasError.detail
+ debug: hasError.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.BadRequest:
return notify2({
type: "error",
title: i18n2.str`The operation id is invalid.`,
description: hasError.detail.hint,
- debug: hasError.detail
+ debug: hasError.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The operation was not found.`,
description: hasError.detail.hint,
- debug: hasError.detail
+ debug: hasError.detail,
+ when: AbsoluteTime.now()
});
default:
assertUnreachable(hasError);
@@ -29034,6 +31843,7 @@ var RefAmount = k3(InputAmount);
function OldWithdrawalForm({
onOperationCreated,
limit,
+ balance,
routeCancel,
focus,
routeOperationDetails
@@ -29041,8 +31851,8 @@ function OldWithdrawalForm({
const { i18n: i18n2 } = useTranslationContext();
const [settings] = usePreferences();
const [bankState, updateBankState] = useBankState();
- const { api } = useBankCoreApiContext();
- const { state: credentials } = useBackendState();
+ const { lib: { bank: api }, config } = useBankCoreApiContext();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
const [amountStr, setAmountStr] = p3(
`${settings.maxWithdrawalAmount}`
@@ -29052,17 +31862,28 @@ function OldWithdrawalForm({
const url = routeOperationDetails.url({
wopid: bankState.currentWithdrawalOperationId
});
- return /* @__PURE__ */ h(Attention, { type: "warning", title: i18n2.str`There is an operation already`, onClose: () => {
- updateBankState("currentWithdrawalOperationId", void 0);
- } }, /* @__PURE__ */ h("span", { ref: focus ? doAutoFocus : void 0 }), /* @__PURE__ */ h(i18n2.Translate, null, "Complete the operation in"), " ", /* @__PURE__ */ h(
- "a",
+ return /* @__PURE__ */ h(
+ Attention,
{
- class: "font-semibold text-yellow-700 hover:text-yellow-600",
- name: "complete operation",
- href: url
+ type: "warning",
+ title: i18n2.str`There is an operation already`,
+ onClose: () => {
+ updateBankState("currentWithdrawalOperationId", void 0);
+ }
},
- /* @__PURE__ */ h(i18n2.Translate, null, "this page")
- ));
+ /* @__PURE__ */ h("span", { ref: focus ? doAutoFocus : void 0 }),
+ /* @__PURE__ */ h(i18n2.Translate, null, "Complete the operation in"),
+ " ",
+ /* @__PURE__ */ h(
+ "a",
+ {
+ class: "font-semibold text-yellow-700 hover:text-yellow-600",
+ name: "complete operation",
+ href: url
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "this page")
+ )
+ );
}
const trimmedAmountStr = amountStr?.trim();
const parsedAmount = trimmedAmountStr ? Amounts.parse(`${limit.currency}:${trimmedAmountStr}`) : void 0;
@@ -29097,7 +31918,8 @@ function OldWithdrawalForm({
type: "error",
title: i18n2.str`The operation was rejected due to insufficient funds`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
break;
}
@@ -29106,7 +31928,8 @@ function OldWithdrawalForm({
type: "error",
title: i18n2.str`The operation was rejected due to insufficient funds`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
break;
}
@@ -29115,7 +31938,8 @@ function OldWithdrawalForm({
type: "error",
title: i18n2.str`Account not found`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
break;
}
@@ -29148,7 +31972,19 @@ function OldWithdrawalForm({
error: errors2?.amount,
ref: focus ? doAutoFocus : void 0
}
- ))), /* @__PURE__ */ h("div", { class: "mt-4" }, /* @__PURE__ */ h("div", { class: "sm:inline" }, /* @__PURE__ */ h(
+ ))), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Current balance is", " ", /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: balance,
+ spec: config.currency_specification
+ }
+ ))), Amounts.cmp(limit, balance) > 0 ? /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Your account allows you to withdraw", " ", /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: limit,
+ spec: config.currency_specification
+ }
+ ))) : void 0, /* @__PURE__ */ h("div", { class: "mt-4" }, /* @__PURE__ */ h("div", { class: "sm:inline" }, /* @__PURE__ */ h(
"button",
{
type: "button",
@@ -29223,6 +32059,7 @@ function OldWithdrawalForm({
function WalletWithdrawForm({
focus,
limit,
+ balance,
routeCancel,
onAuthorizationRequired,
onOperationCreated,
@@ -29231,7 +32068,7 @@ function WalletWithdrawForm({
}) {
const { i18n: i18n2 } = useTranslationContext();
const [settings, updateSettings] = usePreferences();
- return /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Prepare your Taler wallet")), /* @__PURE__ */ h("p", { class: "mt-1 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "After using your wallet you will need to confirm or cancel the operation on this site."))), /* @__PURE__ */ h("div", { class: "col-span-2" }, settings.showInstallWallet && /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Prepare your Taler wallet")), /* @__PURE__ */ h("p", { class: "mt-1 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "After using your wallet you will need to confirm or cancel the operation on this site."))), /* @__PURE__ */ h("div", { class: "col-span-2" }, settings.showInstallWallet && /* @__PURE__ */ h(
Attention,
{
title: i18n2.str`You need a Taler wallet`,
@@ -29258,6 +32095,7 @@ function WalletWithdrawForm({
focus,
routeOperationDetails,
limit,
+ balance,
routeCancel,
onOperationCreated
}
@@ -29274,13 +32112,12 @@ function WalletWithdrawForm({
}
// src/pages/PaymentOptions.tsx
-init_hooks_module();
function ShowOperationPendingTag({
woid,
onOperationAlreadyCompleted
}) {
const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const result = useWithdrawalDetails(woid);
const loading = !result;
const error2 = !loading && (result instanceof TalerError || result.type === "fail");
@@ -29310,6 +32147,7 @@ function PaymentOptions({
routeWireTransfer,
tab,
limit,
+ balance,
onOperationCreated,
onClose,
routeOperationDetails,
@@ -29384,6 +32222,7 @@ function PaymentOptions({
routeOperationDetails,
focus: true,
limit,
+ balance,
onAuthorizationRequired,
onOperationCreated,
onOperationAborted: onClose,
@@ -29393,9 +32232,9 @@ function PaymentOptions({
PaytoWireTransferForm,
{
focus: true,
- title: i18n2.str`Transfer details`,
routeHere: routeWireTransfer,
limit,
+ balance,
onAuthorizationRequired,
onSuccess: onClose,
routeCashout,
@@ -29409,7 +32248,9 @@ function InvalidIbanView({ error: error2 }) {
return /* @__PURE__ */ h("div", null, 'Payto from server is not valid "', error2.payto_uri, '"');
}
var IS_PUBLIC_ACCOUNT_ENABLED = false;
-function ShowDemoInfo({ routePublicAccounts }) {
+function ShowDemoInfo({
+ routePublicAccounts
+}) {
const { i18n: i18n2 } = useTranslationContext();
const [settings, updateSettings] = usePreferences();
if (!settings.showDemoDescription)
@@ -29425,7 +32266,9 @@ function ShowDemoInfo({ routePublicAccounts }) {
IS_PUBLIC_ACCOUNT_ENABLED ? /* @__PURE__ */ h(i18n2.Translate, null, "This part of the demo shows how a bank that supports Taler directly would work. In addition to using your own bank account, you can also see the transaction history of some", " ", /* @__PURE__ */ h("a", { name: "public account", href: routePublicAccounts.url({}) }, "Public Accounts"), ".") : /* @__PURE__ */ h(i18n2.Translate, null, "This part of the demo shows how a bank that supports Taler directly would work.")
);
}
-function ShowPedingOperation({ routeSolveSecondFactor }) {
+function ShowPedingOperation({
+ routeSolveSecondFactor
+}) {
const { i18n: i18n2 } = useTranslationContext();
const [bankState, updateBankState] = useBankState();
if (!bankState.currentChallenge)
@@ -29474,6 +32317,7 @@ function ReadyView3({
routeChargeWallet,
routeWireTransfer,
limit,
+ balance,
routeCashout,
routeCreateWireTransfer,
routePublicAccounts,
@@ -29493,12 +32337,19 @@ function ReadyView3({
routeChargeWallet,
routeWireTransfer,
limit,
+ balance,
routeClose,
onClose,
onOperationCreated,
onAuthorizationRequired
}
- ), /* @__PURE__ */ h(Transactions, { account, routeCreateWireTransfer }));
+ ), /* @__PURE__ */ h(
+ Transactions,
+ {
+ account,
+ routeCreateWireTransfer
+ }
+ ));
}
// src/pages/AccountPage/index.ts
@@ -29517,7 +32368,7 @@ var AccountPage = utils_exports.compose(
// src/pages/BankFrame.tsx
init_preact_module();
init_hooks_module();
-var GIT_HASH = true ? "f6338c00a2740e3eae1079d6c613b95528020c6f" : void 0;
+var GIT_HASH = true ? "d57c7effa9ce2488131176c87af9d57ee5b799b1" : void 0;
var VERSION = true ? "0.9.3-dev.29" : void 0;
function BankFrame({
children,
@@ -29525,7 +32376,7 @@ function BankFrame({
routeAccountDetails
}) {
const { i18n: i18n2 } = useTranslationContext();
- const backend = useBackendState();
+ const session = useSessionState();
const settings = useSettingsContext();
const [preferences, updatePreferences] = usePreferences();
const [, , resetBankState] = useBankState();
@@ -29557,16 +32408,17 @@ function BankFrame({
title: "Bank",
iconLinkURL: settings.iconLinkURL ?? "#",
profileURL: routeAccountDetails?.url({}),
- onLogout: backend.state.status !== "loggedIn" ? void 0 : () => {
- backend.logOut();
+ notificationURL: preferences.showDebugInfo ? privatePages.notifications.url({}) : void 0,
+ onLogout: session.state.status !== "loggedIn" ? void 0 : () => {
+ session.logOut();
resetBankState();
},
sites: !settings.topNavSites ? [] : Object.entries(settings.topNavSites),
supportedLangs: ["en", "es", "de"]
},
- /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("div", { class: "text-xs font-semibold leading-6 text-gray-400" }, /* @__PURE__ */ h(i18n2.Translate, null, "Preferences")), /* @__PURE__ */ h("ul", { role: "list", class: "space-y-1" }, getAllBooleanPreferences().map((set) => {
+ /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("div", { class: "text-xs font-semibold leading-6 text-gray-400" }, /* @__PURE__ */ h(i18n2.Translate, null, "Preferences")), /* @__PURE__ */ h("ul", { role: "list", class: "space-y-4" }, getAllBooleanPreferences().map((set) => {
const isOn = !!preferences[set];
- return /* @__PURE__ */ h("li", { key: set, class: "mt-2 pl-2" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("li", { key: set, class: "pl-2" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
"span",
{
class: "text-sm text-black font-medium leading-6 ",
@@ -29599,8 +32451,15 @@ function BankFrame({
)));
})))
)),
- /* @__PURE__ */ h("div", { class: "fixed z-20 w-full" }, /* @__PURE__ */ h("div", { class: "mx-auto w-4/5" }, /* @__PURE__ */ h(ToastBanner, null))),
- /* @__PURE__ */ h("main", { class: "-mt-32 flex-1" }, account && routeAccountDetails && /* @__PURE__ */ h("header", { class: "py-5 bg-indigo-600 " }, /* @__PURE__ */ h("div", { class: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8" }, /* @__PURE__ */ h("h1", { class: " flex flex-wrap items-center justify-between sm:flex-nowrap" }, /* @__PURE__ */ h("span", { class: "text-2xl font-bold tracking-tight text-white" }, /* @__PURE__ */ h(WelcomeAccount, { account, routeAccountDetails })), /* @__PURE__ */ h("span", { class: "text-2xl font-bold tracking-tight text-white" }, /* @__PURE__ */ h(AccountBalance, { account }))))), /* @__PURE__ */ h("div", { class: "mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8" }, /* @__PURE__ */ h("div", { class: "rounded-lg bg-white px-5 py-6 shadow sm:px-6" }, children))),
+ /* @__PURE__ */ h("div", { class: "fixed z-20 top-14 w-full" }, /* @__PURE__ */ h("div", { class: "mx-auto w-4/5" }, /* @__PURE__ */ h(ToastBanner, null))),
+ /* @__PURE__ */ h("main", { class: "-mt-32 flex-1" }, account && routeAccountDetails && /* @__PURE__ */ h("header", { class: "py-6 bg-indigo-600" }, /* @__PURE__ */ h("div", { class: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8" }, /* @__PURE__ */ h("h1", { class: " flex flex-wrap items-center justify-between sm:flex-nowrap" }, /* @__PURE__ */ h("span", { class: "text-2xl font-bold tracking-tight text-white" }, /* @__PURE__ */ h(
+ WelcomeAccount,
+ {
+ account,
+ routeAccountDetails
+ }
+ )), /* @__PURE__ */ h("span", { class: "text-2xl font-bold tracking-tight text-white" }, /* @__PURE__ */ h(AccountBalance, { account }))))), /* @__PURE__ */ h("div", { class: "mx-auto max-w-7xl px-4 pb-4 sm:px-6 lg:px-8" }, /* @__PURE__ */ h("div", { class: "rounded-lg bg-white px-5 py-6 shadow sm:px-6" }, children))),
+ /* @__PURE__ */ h(AppActivity, null),
/* @__PURE__ */ h(
Footer,
{
@@ -29611,7 +32470,106 @@ function BankFrame({
)
);
}
-function WelcomeAccount({ account, routeAccountDetails }) {
+function Wait2({ class: clazz }) {
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("style", null, `
+ .animated-loader {
+ display: inline-block;
+ --b: 5px;
+ border-radius: 50%;
+ aspect-ratio: 1;
+ padding: 1px;
+ background: conic-gradient(#0000 10%,#4f46e5) content-box;
+ -webkit-mask:
+ repeating-conic-gradient(#0000 0deg,#000 1deg 20deg,#0000 21deg 36deg),
+ radial-gradient(farthest-side,#0000 calc(100% - var(--b) - 1px),#000 calc(100% - var(--b)));
+ -webkit-mask-composite: destination-in;
+ mask-composite: intersect;
+ animation:spinning-loader 1s infinite steps(10);
+ }
+ @keyframes spinning-loader {to{transform: rotate(1turn)}}
+ `), /* @__PURE__ */ h("div", { class: `animated-loader ${clazz}` }));
+}
+function AppActivity() {
+ const [lastEvent, setLastEvent] = p3();
+ const [status, setStatus] = p3();
+ const d5 = useBankCoreApiContext();
+ const onBackendActivity = !d5 ? void 0 : d5.onActivity;
+ const cancelRequest = !d5 ? void 0 : d5.cancelRequest;
+ const [pref] = usePreferences();
+ h2(() => {
+ if (!pref.showDebugInfo)
+ return;
+ if (!onBackendActivity)
+ return;
+ return onBackendActivity((ev) => {
+ switch (ev.type) {
+ case ObservabilityEventType.HttpFetchStart: {
+ setLastEvent(ev);
+ setStatus(void 0);
+ return;
+ }
+ case ObservabilityEventType.HttpFetchFinishError: {
+ setStatus("fail");
+ return;
+ }
+ case ObservabilityEventType.HttpFetchFinishSuccess: {
+ setStatus("ok");
+ return;
+ }
+ case ObservabilityEventType.DbQueryStart:
+ case ObservabilityEventType.DbQueryFinishSuccess:
+ case ObservabilityEventType.DbQueryFinishError:
+ case ObservabilityEventType.RequestStart:
+ case ObservabilityEventType.RequestFinishSuccess:
+ case ObservabilityEventType.RequestFinishError:
+ case ObservabilityEventType.TaskStart:
+ case ObservabilityEventType.TaskStop:
+ case ObservabilityEventType.TaskReset:
+ case ObservabilityEventType.ShepherdTaskResult:
+ case ObservabilityEventType.DeclareTaskDependency:
+ case ObservabilityEventType.CryptoStart:
+ case ObservabilityEventType.CryptoFinishSuccess:
+ case ObservabilityEventType.CryptoFinishError:
+ return;
+ default: {
+ assertUnreachable(ev);
+ }
+ }
+ });
+ });
+ if (!pref.showDebugInfo || !lastEvent)
+ return /* @__PURE__ */ h(p2, null);
+ return /* @__PURE__ */ h(
+ "div",
+ {
+ "data-status": status,
+ class: "fixed z-20 bottom-0 w-full ease-in-out delay-1000 transition-transform data-[status=ok]:scale-y-0"
+ },
+ /* @__PURE__ */ h(
+ "div",
+ {
+ "data-status": status,
+ class: "mx-auto w-4/5 center flex p-1 bg-gray-300 m-1 data-[status=fail]:bg-red-200 data-[status=ok]:bg-green-200 "
+ },
+ !status ? /* @__PURE__ */ h(Wait2, { class: "w-6 h-6" }) : /* @__PURE__ */ h("div", { class: "w-6 h-6" }),
+ /* @__PURE__ */ h("p", { class: "ml-2 my-auto text-sm text-gray-500" }, lastEvent.url),
+ !status ? /* @__PURE__ */ h(
+ "button",
+ {
+ onClick: () => {
+ if (cancelRequest)
+ cancelRequest(lastEvent.id);
+ }
+ },
+ "cancel"
+ ) : void 0
+ )
+ );
+}
+function WelcomeAccount({
+ account,
+ routeAccountDetails
+}) {
const { i18n: i18n2 } = useTranslationContext();
const result = useAccountDetails(account);
if (!result) {
@@ -29662,998 +32620,6 @@ function AccountBalance({ account }) {
);
}
-// src/pages/DownloadStats.tsx
-init_preact_module();
-init_hooks_module();
-
-// src/pages/admin/AdminHome.tsx
-init_preact_module();
-init_hooks_module();
-
-// src/pages/WireTransfer.tsx
-init_preact_module();
-function WireTransfer({
- toAccount,
- withSubject,
- withAmount,
- onAuthorizationRequired,
- routeCancel,
- routeHere,
- onSuccess
-}) {
- const { i18n: i18n2 } = useTranslationContext();
- const r3 = useBackendState();
- const account = r3.state.status !== "loggedOut" ? r3.state.username : "admin";
- const result = useAccountDetails(account);
- if (!result) {
- return /* @__PURE__ */ h(Loading, null);
- }
- if (result instanceof TalerError) {
- return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: result });
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.Unauthorized:
- return /* @__PURE__ */ h(LoginForm, { currentUser: account });
- case HttpStatusCode.NotFound:
- return /* @__PURE__ */ h(LoginForm, { currentUser: account });
- default:
- assertUnreachable(result);
- }
- }
- const { body: data } = result;
- const balance = Amounts.parseOrThrow(data.balance.amount);
- const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
- const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
- const limit = balanceIsDebit ? Amounts.sub(debitThreshold, balance).amount : Amounts.add(balance, debitThreshold).amount;
- if (!balance)
- return /* @__PURE__ */ h(p2, null);
- return /* @__PURE__ */ h(
- PaytoWireTransferForm,
- {
- title: i18n2.str`Make a wire transfer`,
- withAccount: toAccount,
- withAmount,
- withSubject,
- routeHere,
- limit,
- onAuthorizationRequired,
- onSuccess: () => {
- notifyInfo(i18n2.str`Wire transfer created!`);
- if (onSuccess)
- onSuccess();
- },
- routeCancel
- }
- );
-}
-
-// src/pages/admin/AccountList.tsx
-init_preact_module();
-function AccountList({
- routeCreate,
- routeRemoveAccount,
- routeShowAccount,
- routeShowCashoutsAccount,
- routeUpdatePasswordAccount
-}) {
- const result = useBusinessAccounts();
- const { i18n: i18n2 } = useTranslationContext();
- const { config } = useBankCoreApiContext();
- if (!result) {
- return /* @__PURE__ */ h(Loading, null);
- }
- if (result instanceof TalerError) {
- return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: result });
- }
- if (result.data.type === "fail") {
- switch (result.data.case) {
- case HttpStatusCode.Unauthorized:
- return /* @__PURE__ */ h(p2, null);
- default:
- assertUnreachable(result.data.case);
- }
- }
- const onGoStart = result.isFirstPage ? void 0 : result.loadFirst;
- const onGoNext = result.isLastPage ? void 0 : result.loadNext;
- const accounts = result.result;
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 sm:px-6 lg:px-8 mt-4" }, /* @__PURE__ */ h("div", { class: "sm:flex sm:items-center" }, /* @__PURE__ */ h("div", { class: "sm:flex-auto" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Accounts")), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-700" }, /* @__PURE__ */ h(i18n2.Translate, null, "A list of all bank accounts."))), /* @__PURE__ */ h("div", { class: "mt-4 sm:ml-16 sm:mt-0 sm:flex-none" }, /* @__PURE__ */ h(
- "a",
- {
- href: routeCreate.url({}),
- name: "create account",
- type: "button",
- class: "block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Create account")
- ))), /* @__PURE__ */ h("div", { class: "mt-8 flow-root" }, /* @__PURE__ */ h("div", { class: "-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8" }, /* @__PURE__ */ h("div", { class: "inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8" }, !accounts.length ? /* @__PURE__ */ h("div", null) : /* @__PURE__ */ h("table", { class: "min-w-full divide-y divide-gray-300" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h(
- "th",
- {
- scope: "col",
- class: "py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0"
- },
- i18n2.str`Username`
- ), /* @__PURE__ */ h(
- "th",
- {
- scope: "col",
- class: "px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
- },
- i18n2.str`Name`
- ), /* @__PURE__ */ h(
- "th",
- {
- scope: "col",
- class: "px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
- },
- i18n2.str`Balance`
- ), /* @__PURE__ */ h("th", { scope: "col", class: "relative py-3.5 pl-3 pr-4 sm:pr-0" }, /* @__PURE__ */ h("span", { class: "sr-only" }, i18n2.str`Actions`)))), /* @__PURE__ */ h("tbody", { class: "divide-y divide-gray-200" }, accounts.map((item, idx) => {
- const balance = !item.balance ? void 0 : Amounts.parse(item.balance.amount);
- const noBalance = Amounts.isZero(item.balance.amount);
- const balanceIsDebit = item.balance && item.balance.credit_debit_indicator == "debit";
- return /* @__PURE__ */ h("tr", { key: idx }, /* @__PURE__ */ h("td", { class: "whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-0" }, /* @__PURE__ */ h(
- "a",
- {
- name: `show account ${item.username}`,
- href: routeShowAccount.url({
- account: item.username
- }),
- class: "text-indigo-600 hover:text-indigo-900"
- },
- item.username
- )), /* @__PURE__ */ h("td", { class: "whitespace-nowrap px-3 py-4 text-sm text-gray-500" }, item.name), /* @__PURE__ */ h(
- "td",
- {
- "data-negative": noBalance ? void 0 : balanceIsDebit ? "true" : "false",
- class: "whitespace-nowrap px-3 py-4 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600 "
- },
- !balance ? i18n2.str`Unknown` : /* @__PURE__ */ h("span", { class: "amount" }, /* @__PURE__ */ h(
- RenderAmount,
- {
- value: balance,
- negative: balanceIsDebit,
- spec: config.currency_specification
- }
- ))
- ), /* @__PURE__ */ h("td", { class: "relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0" }, /* @__PURE__ */ h(
- "a",
- {
- name: `update password ${item.username}`,
- href: routeUpdatePasswordAccount.url({
- account: item.username
- }),
- class: "text-indigo-600 hover:text-indigo-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Change password")
- ), /* @__PURE__ */ h("br", null), noBalance ? /* @__PURE__ */ h(
- "a",
- {
- name: `remove account ${item.username}`,
- href: routeRemoveAccount.url({
- account: item.username
- }),
- class: "text-indigo-600 hover:text-indigo-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Remove")
- ) : void 0));
- })))), /* @__PURE__ */ h(
- "nav",
- {
- class: "flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg",
- "aria-label": "Pagination"
- },
- /* @__PURE__ */ h("div", { class: "flex flex-1 justify-between sm:justify-end" }, /* @__PURE__ */ h(
- "button",
- {
- name: "first page",
- class: "relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0",
- disabled: !onGoStart,
- onClick: onGoStart
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "First page")
- ), /* @__PURE__ */ h(
- "button",
- {
- name: "next page",
- class: "relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0",
- disabled: !onGoNext,
- onClick: onGoNext
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Next")
- ))
- )))));
-}
-
-// src/pages/admin/AdminHome.tsx
-function AdminHome({
- routeCreate,
- routeRemoveAccount,
- routeShowAccount,
- routeShowCashoutsAccount,
- routeUpdatePasswordAccount,
- routeDownloadStats,
- routeCreateWireTransfer,
- onAuthorizationRequired
-}) {
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(Metrics, { routeDownloadStats }), /* @__PURE__ */ h(WireTransfer, { routeHere: routeCreateWireTransfer, onAuthorizationRequired }), /* @__PURE__ */ h(
- Transactions,
- {
- account: "admin",
- routeCreateWireTransfer
- }
- ), /* @__PURE__ */ h(
- AccountList,
- {
- routeCreate,
- routeRemoveAccount,
- routeShowAccount,
- routeShowCashoutsAccount,
- routeUpdatePasswordAccount
- }
- ));
-}
-function getDateForTimeframe(which, timeframe, locale6) {
- const time = Date.now();
- switch (timeframe) {
- case TalerCorebankApi.MonitorTimeframeParam.hour:
- return `${format(setHours(time, which), "HH", { locale: locale6 })}hs`;
- case TalerCorebankApi.MonitorTimeframeParam.day:
- return format(setDate(time, which), "EEEE", { locale: locale6 });
- case TalerCorebankApi.MonitorTimeframeParam.month:
- return format(setMonth(time, which), "MMMM", { locale: locale6 });
- case TalerCorebankApi.MonitorTimeframeParam.year:
- return format(setYear(time, which), "yyyy", { locale: locale6 });
- case TalerCorebankApi.MonitorTimeframeParam.decade:
- return format(setYear(time, which), "yyyy", { locale: locale6 });
- }
- assertUnreachable(timeframe);
-}
-function getTimeframesForDate(time, timeframe) {
- switch (timeframe) {
- case TalerCorebankApi.MonitorTimeframeParam.hour:
- return {
- current: getHours(sub(time, { hours: 1 })),
- previous: getHours(sub(time, { hours: 2 }))
- };
- case TalerCorebankApi.MonitorTimeframeParam.day:
- return {
- current: getDate(sub(time, { days: 1 })),
- previous: getDate(sub(time, { days: 2 }))
- };
- case TalerCorebankApi.MonitorTimeframeParam.month:
- return {
- current: getMonth(sub(time, { months: 1 })),
- previous: getMonth(sub(time, { months: 2 }))
- };
- case TalerCorebankApi.MonitorTimeframeParam.year:
- return {
- current: getYear(sub(time, { years: 1 })),
- previous: getYear(sub(time, { years: 2 }))
- };
- case TalerCorebankApi.MonitorTimeframeParam.decade:
- return {
- current: getYear(sub(time, { years: 10 })),
- previous: getYear(sub(time, { years: 20 }))
- };
- default:
- assertUnreachable(timeframe);
- }
-}
-function Metrics({
- routeDownloadStats
-}) {
- const { i18n: i18n2, dateLocale } = useTranslationContext();
- const [metricType, setMetricType] = p3(
- TalerCorebankApi.MonitorTimeframeParam.hour
- );
- const { config } = useBankCoreApiContext();
- const respInfo = useConversionInfo();
- const params = getTimeframesForDate(/* @__PURE__ */ new Date(), metricType);
- const resp = useLastMonitorInfo(params.current, params.previous, metricType);
- if (!resp)
- return /* @__PURE__ */ h(p2, null);
- if (resp instanceof TalerError) {
- return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: resp });
- }
- if (!respInfo)
- return /* @__PURE__ */ h(p2, null);
- if (respInfo instanceof TalerError) {
- return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: respInfo });
- }
- if (respInfo.type === "fail") {
- switch (respInfo.case) {
- case HttpStatusCode.NotImplemented: {
- return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
- }
- default:
- assertUnreachable(respInfo.case);
- }
- }
- if (resp.current.type !== "ok" || resp.previous.type !== "ok") {
- return /* @__PURE__ */ h(p2, null);
- }
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "sm:hidden" }, /* @__PURE__ */ h("label", { for: "tabs", class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Select a section")), /* @__PURE__ */ h(
- "select",
- {
- id: "tabs",
- name: "tabs",
- class: "block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500",
- onChange: (e4) => {
- setMetricType(
- e4.currentTarget.value
- );
- }
- },
- /* @__PURE__ */ h(
- "option",
- {
- value: TalerCorebankApi.MonitorTimeframeParam.hour,
- selected: metricType == TalerCorebankApi.MonitorTimeframeParam.hour
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Last hour")
- ),
- /* @__PURE__ */ h(
- "option",
- {
- value: TalerCorebankApi.MonitorTimeframeParam.day,
- selected: metricType == TalerCorebankApi.MonitorTimeframeParam.day
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Previous day")
- ),
- /* @__PURE__ */ h(
- "option",
- {
- value: TalerCorebankApi.MonitorTimeframeParam.month,
- selected: metricType == TalerCorebankApi.MonitorTimeframeParam.month
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Last month")
- ),
- /* @__PURE__ */ h(
- "option",
- {
- value: TalerCorebankApi.MonitorTimeframeParam.year,
- selected: metricType == TalerCorebankApi.MonitorTimeframeParam.year
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Last year")
- )
- )), /* @__PURE__ */ h("div", { class: "hidden sm:block" }, /* @__PURE__ */ h(
- "nav",
- {
- class: "isolate flex divide-x divide-gray-200 rounded-lg shadow",
- "aria-label": "Tabs"
- },
- /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: "set last hour",
- onClick: (e4) => {
- e4.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.hour);
- },
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.hour,
- class: "rounded-l-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- },
- /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Last hour")),
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.hour,
- class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- }
- )
- ),
- /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: "set previous day",
- onClick: (e4) => {
- e4.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.day);
- },
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.day,
- class: " text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- },
- /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Previous day")),
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.day,
- class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- }
- )
- ),
- /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: "set last month",
- onClick: (e4) => {
- e4.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.month);
- },
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.month,
- class: "rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- },
- /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Last month")),
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.month,
- class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- }
- )
- ),
- /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: "set last year",
- onClick: (e4) => {
- e4.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.year);
- },
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.year,
- class: "rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- },
- /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Last Year")),
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.year,
- class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- }
- )
- )
- )), /* @__PURE__ */ h("div", { class: "w-full flex justify-between" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-7 text-gray-900 mt-5" }, i18n2.str`Trading volume on ${getDateForTimeframe(
- params.current,
- metricType,
- dateLocale
- )} compared to ${getDateForTimeframe(
- params.previous,
- metricType,
- dateLocale
- )}`)), /* @__PURE__ */ h("dl", { class: "mt-5 grid grid-cols-1 md:grid-cols-2 divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0" }, resp.current.body.type !== "with-conversions" || resp.previous.body.type !== "with-conversions" ? void 0 : /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashin"), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from an external account to an account in this bank."))), /* @__PURE__ */ h(
- MetricValue,
- {
- current: resp.current.body.cashinFiatVolume,
- previous: resp.previous.body.cashinFiatVolume,
- spec: respInfo.body.fiat_currency_specification
- }
- )), /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout")), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from an account in this bank to an external account.")), /* @__PURE__ */ h(
- MetricValue,
- {
- current: resp.current.body.cashoutFiatVolume,
- previous: resp.previous.body.cashoutFiatVolume,
- spec: respInfo.body.fiat_currency_specification
- }
- ))), /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payin"), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from an account to a Taler exchange."))), /* @__PURE__ */ h(
- MetricValue,
- {
- current: resp.current.body.talerInVolume,
- previous: resp.previous.body.talerInVolume,
- spec: config.currency_specification
- }
- )), /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payout"), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from a Taler exchange to another account."))), /* @__PURE__ */ h(
- MetricValue,
- {
- current: resp.current.body.talerOutVolume,
- previous: resp.previous.body.talerOutVolume,
- spec: config.currency_specification
- }
- ))), /* @__PURE__ */ h("div", { class: "flex justify-end mt-2" }, /* @__PURE__ */ h(
- "a",
- {
- href: routeDownloadStats.url({}),
- name: "download stats",
- class: "disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Download stats as CSV")
- )));
-}
-function MetricValue({
- current,
- previous,
- spec
-}) {
- const { i18n: i18n2 } = useTranslationContext();
- const cmp = current && previous ? Amounts.cmp(current, previous) : 0;
- const cv = !current ? void 0 : Amounts.stringifyValue(current);
- const currAmount = !cv ? void 0 : Number.parseFloat(cv);
- const prevAmount = !previous ? void 0 : Number.parseFloat(Amounts.stringifyValue(previous));
- const rate = !currAmount || Number.isNaN(currAmount) || !prevAmount || Number.isNaN(prevAmount) ? 0 : cmp === -1 ? 1 - Math.round(currAmount) / Math.round(prevAmount) : cmp === 1 ? Math.round(currAmount) / Math.round(prevAmount) - 1 : 0;
- const negative = cmp === 0 ? void 0 : cmp === -1;
- const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`;
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("dd", { class: "mt-1 block " }, /* @__PURE__ */ h("div", { class: "flex justify-start text-2xl items-baseline font-semibold text-indigo-600" }, !current ? "-" : /* @__PURE__ */ h(
- RenderAmount,
- {
- value: Amounts.parseOrThrow(current),
- spec,
- hideSmall: true
- }
- )), /* @__PURE__ */ h("div", { class: "flex flex-col" }, /* @__PURE__ */ h("div", { class: "flex justify-end items-baseline text-2xl font-semibold text-indigo-600" }, /* @__PURE__ */ h("small", { class: "ml-2 text-sm font-medium text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "from"), " ", !previous ? "-" : /* @__PURE__ */ h(
- RenderAmount,
- {
- value: Amounts.parseOrThrow(previous),
- spec,
- hideSmall: true
- }
- ))), !!rate && /* @__PURE__ */ h(
- "span",
- {
- "data-negative": negative,
- class: "flex items-center gap-x-1.5 w-fit rounded-md bg-green-100 text-green-800 data-[negative=true]:bg-red-100 px-2 py-1 text-xs font-medium data-[negative=true]:text-red-700 whitespace-pre"
- },
- negative ? /* @__PURE__ */ h(
- "svg",
- {
- xmlns: "http://www.w3.org/2000/svg",
- fill: "none",
- viewBox: "0 0 24 24",
- "stroke-width": "1.5",
- stroke: "currentColor",
- class: "w-6 h-6"
- },
- /* @__PURE__ */ h(
- "path",
- {
- "stroke-linecap": "round",
- "stroke-linejoin": "round",
- d: "M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
- }
- )
- ) : /* @__PURE__ */ h(
- "svg",
- {
- xmlns: "http://www.w3.org/2000/svg",
- fill: "none",
- viewBox: "0 0 24 24",
- "stroke-width": "1.5",
- stroke: "currentColor",
- class: "w-6 h-6"
- },
- /* @__PURE__ */ h(
- "path",
- {
- "stroke-linecap": "round",
- "stroke-linejoin": "round",
- d: "M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75"
- }
- )
- ),
- negative ? /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Decreased by")) : /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Increased by")),
- rateStr
- ))));
-}
-
-// src/pages/DownloadStats.tsx
-function DownloadStats({ routeCancel }) {
- const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
- const creds = credentials.status !== "loggedIn" || !credentials.isUserAdministrator ? void 0 : credentials;
- const { api } = useBankCoreApiContext();
- const [options, setOptions] = p3({
- compareWithPrevious: true,
- dayMetric: true,
- endOnFirstFail: false,
- hourMetric: true,
- includeHeader: true,
- monthMetric: true,
- yearMetric: true
- });
- const [lastStep, setLastStep] = p3();
- const [downloaded, setDownloaded] = p3();
- const referenceDates = [/* @__PURE__ */ new Date()];
- const [notification, , handleError] = useLocalNotification();
- if (!creds) {
- return /* @__PURE__ */ h("div", null, "only admin can download stats");
- }
- return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Download bank stats"))), /* @__PURE__ */ h(
- "form",
- {
- class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2",
- autoCapitalize: "none",
- autoCorrect: "off",
- onSubmit: (e4) => {
- e4.preventDefault();
- }
- },
- /* @__PURE__ */ h("div", { class: "px-4 py-6 sm:p-8" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Include hour metric")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `hour switch`,
- "data-enabled": options.hourMetric,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({
- ...options,
- hourMetric: !options.hourMetric
- });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.hourMetric,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Include day metric")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `day switch`,
- "data-enabled": !!options.dayMetric,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({ ...options, dayMetric: !options.dayMetric });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.dayMetric,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Include month metric")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `month switch`,
- "data-enabled": !!options.monthMetric,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({
- ...options,
- monthMetric: !options.monthMetric
- });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.monthMetric,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Include year metric")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `year switch`,
- "data-enabled": !!options.yearMetric,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({
- ...options,
- yearMetric: !options.yearMetric
- });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.yearMetric,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Include table header")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `header switch`,
- "data-enabled": !!options.includeHeader,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({
- ...options,
- includeHeader: !options.includeHeader
- });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.includeHeader,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Add previous metric for compare")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `compare switch`,
- "data-enabled": !!options.compareWithPrevious,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({
- ...options,
- compareWithPrevious: !options.compareWithPrevious
- });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.compareWithPrevious,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-medium leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Fail on first error")
- )), /* @__PURE__ */ h(
- "button",
- {
- type: "button",
- name: `fail switch`,
- "data-enabled": !!options.endOnFirstFail,
- class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
- role: "switch",
- "aria-checked": "false",
- "aria-labelledby": "availability-label",
- "aria-describedby": "availability-description",
- onClick: () => {
- setOptions({
- ...options,
- endOnFirstFail: !options.endOnFirstFail
- });
- }
- },
- /* @__PURE__ */ h(
- "span",
- {
- "aria-hidden": "true",
- "data-enabled": options.endOnFirstFail,
- class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- }
- )
- ))))),
- /* @__PURE__ */ h("div", { class: "flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8" }, /* @__PURE__ */ h(
- "a",
- {
- name: "cancel",
- href: routeCancel.url({}),
- class: "text-sm font-semibold leading-6 text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")
- ), /* @__PURE__ */ h(
- "button",
- {
- type: "submit",
- name: "download",
- class: "disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
- disabled: lastStep !== void 0,
- onClick: async () => {
- setDownloaded(void 0);
- await handleError(async () => {
- const csv = await fetchAllStatus(
- api,
- creds.token,
- options,
- referenceDates,
- (step, total) => {
- setLastStep({ step, total });
- }
- );
- setDownloaded(csv);
- });
- setLastStep(void 0);
- }
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Download")
- ))
- )), !lastStep || lastStep.step === lastStep.total ? /* @__PURE__ */ h("div", { class: "h-5 mb-5" }) : /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "relative mb-5 h-5 rounded-full bg-gray-200" }, /* @__PURE__ */ h(
- "div",
- {
- class: "h-full animate-pulse rounded-full bg-blue-500",
- style: {
- width: `${Math.round(lastStep.step / lastStep.total * 100)}%`
- }
- },
- /* @__PURE__ */ h("span", { class: "absolute inset-0 flex items-center justify-center text-xs font-semibold text-white" }, /* @__PURE__ */ h(i18n2.Translate, null, "downloading...", " ", Math.round(lastStep.step / lastStep.total * 100)))
- ))), !downloaded ? /* @__PURE__ */ h("div", { class: "h-5 mb-5" }) : /* @__PURE__ */ h(
- "a",
- {
- href: "data:text/plain;charset=utf-8," + encodeURIComponent(downloaded),
- name: "save file",
- download: "bank-stats.csv"
- },
- /* @__PURE__ */ h(Attention, { title: i18n2.str`Download completed` }, /* @__PURE__ */ h(i18n2.Translate, null, "Click here to save the file in your computer."))
- ));
-}
-async function fetchAllStatus(api, token, options, references, progress) {
- const allMetrics = [];
- if (options.hourMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.hour);
- }
- if (options.dayMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.day);
- }
- if (options.monthMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.month);
- }
- if (options.yearMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.year);
- }
- const allFrames = allMetrics.flatMap(
- (timeframe) => references.map((reference) => ({
- reference,
- timeframe,
- moment: getTimeframesForDate(reference, timeframe)
- }))
- );
- const total = allFrames.length;
- const allInfo = await allFrames.reduce(
- async (prev, frame, index) => {
- const accumulatedMap = await prev;
- progress(index, total);
- const previous = options.compareWithPrevious ? await api.getMonitor(token, {
- timeframe: frame.timeframe,
- which: frame.moment.previous
- }) : void 0;
- if (previous && previous.type === "fail" && options.endOnFirstFail) {
- throw TalerError.fromUncheckedDetail(previous.detail);
- }
- const current = await api.getMonitor(token, {
- timeframe: frame.timeframe,
- which: frame.moment.current
- });
- if (current.type === "fail" && options.endOnFirstFail) {
- throw TalerError.fromUncheckedDetail(current.detail);
- }
- const metricName = TalerCorebankApi.MonitorTimeframeParam[allMetrics[index]];
- accumulatedMap[metricName] = {
- reference: frame.reference,
- current: current.type !== "ok" ? void 0 : current.body,
- previous: !previous || previous.type !== "ok" ? void 0 : previous.body
- };
- return accumulatedMap;
- },
- Promise.resolve({})
- );
- progress(total, total);
- const table2 = [];
- if (options.includeHeader) {
- table2.push([
- "date",
- "metric",
- "reference",
- "talerInCount",
- "talerInVolume",
- "talerOutCount",
- "talerOutVolume",
- "cashinCount",
- "cashinFiatVolume",
- "cashinRegionalVolume",
- "cashoutCount",
- "cashoutFiatVolume",
- "cashoutRegionalVolume"
- ]);
- }
- Object.entries(allInfo).forEach(([name, data]) => {
- if (data.current) {
- const row = {
- date: data.reference.getTime(),
- metric: name,
- reference: "current",
- ...dataToRow(data.current)
- };
- table2.push(Object.values(row));
- }
- if (data.previous) {
- const row = {
- date: data.reference.getTime(),
- metric: name,
- reference: "previous",
- ...dataToRow(data.previous)
- };
- table2.push(Object.values(row));
- }
- });
- const csv = table2.reduce((acc, row) => {
- return acc + row.join(",") + "\n";
- }, "");
- return csv;
-}
-function dataToRow(info) {
- return {
- talerInCount: info.talerInCount,
- talerInVolume: info.talerInVolume,
- talerOutCount: info.talerOutCount,
- talerOutVolume: info.talerOutVolume,
- cashinCount: info.type === "no-conversions" ? void 0 : info.cashinCount,
- cashinFiatVolume: info.type === "no-conversions" ? void 0 : info.cashinFiatVolume,
- cashinRegionalVolume: info.type === "no-conversions" ? void 0 : info.cashinRegionalVolume,
- cashoutCount: info.type === "no-conversions" ? void 0 : info.cashoutCount,
- cashoutFiatVolume: info.type === "no-conversions" ? void 0 : info.cashoutFiatVolume,
- cashoutRegionalVolume: info.type === "no-conversions" ? void 0 : info.cashoutRegionalVolume
- };
-}
-
// src/pages/PublicHistoriesPage.tsx
init_preact_module();
init_hooks_module();
@@ -30691,3183 +32657,343 @@ function PublicHistoriesPage() {
)
)
);
- txs[account.username] = /* @__PURE__ */ h(Transactions, { account: account.username, routeCreateWireTransfer: void 0 });
+ txs[account.username] = /* @__PURE__ */ h(
+ Transactions,
+ {
+ account: account.username,
+ routeCreateWireTransfer: void 0
+ }
+ );
}
return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("h1", { class: "nav" }, i18n2.str`History of public accounts`), /* @__PURE__ */ h("section", { id: "main" }, /* @__PURE__ */ h("article", null, /* @__PURE__ */ h("div", { class: "pure-menu pure-menu-horizontal", name: "accountMenu" }, /* @__PURE__ */ h("ul", { class: "pure-menu-list" }, accountsBar), typeof showAccount !== "undefined" ? txs[showAccount] : /* @__PURE__ */ h("p", null, "No public transactions found."), /* @__PURE__ */ h("br", null)))));
}
-// src/pages/RegistrationPage.tsx
+// src/pages/ShowNotifications.tsx
init_preact_module();
-init_hooks_module();
-
-// src/pages/rnd.ts
-var noun = [
- "people",
- "history",
- "way",
- "art",
- "world",
- "information",
- "map",
- "two",
- "family",
- "government",
- "health",
- "system",
- "computer",
- "meat",
- "year",
- "thanks",
- "music",
- "person",
- "reading",
- "method",
- "data",
- "food",
- "understanding",
- "theory",
- "law",
- "bird",
- "literature",
- "problem",
- "software",
- "control",
- "knowledge",
- "power",
- "ability",
- "economics",
- "love",
- "internet",
- "television",
- "science",
- "library",
- "nature",
- "fact",
- "product",
- "idea",
- "temperature",
- "investment",
- "area",
- "society",
- "activity",
- "story",
- "industry",
- "media",
- "thing",
- "oven",
- "community",
- "definition",
- "safety",
- "quality",
- "development",
- "language",
- "management",
- "player",
- "variety",
- "video",
- "week",
- "security",
- "country",
- "exam",
- "movie",
- "organization",
- "equipment",
- "physics",
- "analysis",
- "policy",
- "series",
- "thought",
- "basis",
- "boyfriend",
- "direction",
- "strategy",
- "technology",
- "army",
- "camera",
- "freedom",
- "paper",
- "environment",
- "child",
- "instance",
- "month",
- "truth",
- "marketing",
- "university",
- "writing",
- "article",
- "department",
- "difference",
- "goal",
- "news",
- "audience",
- "fishing",
- "growth",
- "income",
- "marriage",
- "user",
- "combination",
- "failure",
- "meaning",
- "medicine",
- "philosophy",
- "teacher",
- "communication",
- "night",
- "chemistry",
- "disease",
- "disk",
- "energy",
- "nation",
- "road",
- "role",
- "soup",
- "advertising",
- "location",
- "success",
- "addition",
- "apartment",
- "education",
- "math",
- "moment",
- "painting",
- "politics",
- "attention",
- "decision",
- "event",
- "property",
- "shopping",
- "student",
- "wood",
- "competition",
- "distribution",
- "entertainment",
- "office",
- "population",
- "president",
- "unit",
- "category",
- "cigarette",
- "context",
- "introduction",
- "opportunity",
- "performance",
- "driver",
- "flight",
- "length",
- "magazine",
- "newspaper",
- "relationship",
- "teaching",
- "cell",
- "dealer",
- "finding",
- "lake",
- "member",
- "message",
- "phone",
- "scene",
- "appearance",
- "association",
- "concept",
- "customer",
- "death",
- "discussion",
- "housing",
- "inflation",
- "insurance",
- "mood",
- "woman",
- "advice",
- "blood",
- "effort",
- "expression",
- "importance",
- "opinion",
- "payment",
- "reality",
- "responsibility",
- "situation",
- "skill",
- "statement",
- "wealth",
- "application",
- "city",
- "county",
- "depth",
- "estate",
- "foundation",
- "grandmother",
- "heart",
- "perspective",
- "photo",
- "recipe",
- "studio",
- "topic",
- "collection",
- "depression",
- "imagination",
- "passion",
- "percentage",
- "resource",
- "setting",
- "ad",
- "agency",
- "college",
- "connection",
- "criticism",
- "debt",
- "description",
- "memory",
- "patience",
- "secretary",
- "solution",
- "administration",
- "aspect",
- "attitude",
- "director",
- "personality",
- "psychology",
- "recommendation",
- "response",
- "selection",
- "storage",
- "version",
- "alcohol",
- "argument",
- "complaint",
- "contract",
- "emphasis",
- "highway",
- "loss",
- "membership",
- "possession",
- "preparation",
- "steak",
- "union",
- "agreement",
- "cancer",
- "currency",
- "employment",
- "engineering",
- "entry",
- "interaction",
- "mixture",
- "preference",
- "region",
- "republic",
- "tradition",
- "virus",
- "actor",
- "classroom",
- "delivery",
- "device",
- "difficulty",
- "drama",
- "election",
- "engine",
- "football",
- "guidance",
- "hotel",
- "owner",
- "priority",
- "protection",
- "suggestion",
- "tension",
- "variation",
- "anxiety",
- "atmosphere",
- "awareness",
- "bath",
- "bread",
- "candidate",
- "climate",
- "comparison",
- "confusion",
- "construction",
- "elevator",
- "emotion",
- "employee",
- "employer",
- "guest",
- "height",
- "leadership",
- "mall",
- "manager",
- "operation",
- "recording",
- "sample",
- "transportation",
- "charity",
- "cousin",
- "disaster",
- "editor",
- "efficiency",
- "excitement",
- "extent",
- "feedback",
- "guitar",
- "homework",
- "leader",
- "mom",
- "outcome",
- "permission",
- "presentation",
- "promotion",
- "reflection",
- "refrigerator",
- "resolution",
- "revenue",
- "session",
- "singer",
- "tennis",
- "basket",
- "bonus",
- "cabinet",
- "childhood",
- "church",
- "clothes",
- "coffee",
- "dinner",
- "drawing",
- "hair",
- "hearing",
- "initiative",
- "judgment",
- "lab",
- "measurement",
- "mode",
- "mud",
- "orange",
- "poetry",
- "police",
- "possibility",
- "procedure",
- "queen",
- "ratio",
- "relation",
- "restaurant",
- "satisfaction",
- "sector",
- "signature",
- "significance",
- "song",
- "tooth",
- "town",
- "vehicle",
- "volume",
- "wife",
- "accident",
- "airport",
- "appointment",
- "arrival",
- "assumption",
- "baseball",
- "chapter",
- "committee",
- "conversation",
- "database",
- "enthusiasm",
- "error",
- "explanation",
- "farmer",
- "gate",
- "girl",
- "hall",
- "historian",
- "hospital",
- "injury",
- "instruction",
- "maintenance",
- "manufacturer",
- "meal",
- "perception",
- "pie",
- "poem",
- "presence",
- "proposal",
- "reception",
- "replacement",
- "revolution",
- "river",
- "son",
- "speech",
- "tea",
- "village",
- "warning",
- "winner",
- "worker",
- "writer",
- "assistance",
- "breath",
- "buyer",
- "chest",
- "chocolate",
- "conclusion",
- "contribution",
- "cookie",
- "courage",
- "dad",
- "desk",
- "drawer",
- "establishment",
- "examination",
- "garbage",
- "grocery",
- "honey",
- "impression",
- "improvement",
- "independence",
- "insect",
- "inspection",
- "inspector",
- "king",
- "ladder",
- "menu",
- "penalty",
- "piano",
- "potato",
- "profession",
- "professor",
- "quantity",
- "reaction",
- "requirement",
- "salad",
- "sister",
- "supermarket",
- "tongue",
- "weakness",
- "wedding",
- "affair",
- "ambition",
- "analyst",
- "apple",
- "assignment",
- "assistant",
- "bathroom",
- "bedroom",
- "beer",
- "birthday",
- "celebration",
- "championship",
- "cheek",
- "client",
- "consequence",
- "departure",
- "diamond",
- "dirt",
- "ear",
- "fortune",
- "friendship",
- "funeral",
- "gene",
- "girlfriend",
- "hat",
- "indication",
- "intention",
- "lady",
- "midnight",
- "negotiation",
- "obligation",
- "passenger",
- "pizza",
- "platform",
- "poet",
- "pollution",
- "recognition",
- "reputation",
- "shirt",
- "sir",
- "speaker",
- "stranger",
- "surgery",
- "sympathy",
- "tale",
- "throat",
- "trainer",
- "uncle",
- "youth",
- "time",
- "work",
- "film",
- "water",
- "money",
- "example",
- "while",
- "business",
- "study",
- "game",
- "life",
- "form",
- "air",
- "day",
- "place",
- "number",
- "part",
- "field",
- "fish",
- "back",
- "process",
- "heat",
- "hand",
- "experience",
- "job",
- "book",
- "end",
- "point",
- "type",
- "home",
- "economy",
- "value",
- "body",
- "market",
- "guide",
- "interest",
- "state",
- "radio",
- "course",
- "company",
- "price",
- "size",
- "card",
- "list",
- "mind",
- "trade",
- "line",
- "care",
- "group",
- "risk",
- "word",
- "fat",
- "force",
- "key",
- "light",
- "training",
- "name",
- "school",
- "top",
- "amount",
- "level",
- "order",
- "practice",
- "research",
- "sense",
- "service",
- "piece",
- "web",
- "boss",
- "sport",
- "fun",
- "house",
- "page",
- "term",
- "test",
- "answer",
- "sound",
- "focus",
- "matter",
- "kind",
- "soil",
- "board",
- "oil",
- "picture",
- "access",
- "garden",
- "range",
- "rate",
- "reason",
- "future",
- "site",
- "demand",
- "exercise",
- "image",
- "case",
- "cause",
- "coast",
- "action",
- "age",
- "bad",
- "boat",
- "record",
- "result",
- "section",
- "building",
- "mouse",
- "cash",
- "class",
- "nothing",
- "period",
- "plan",
- "store",
- "tax",
- "side",
- "subject",
- "space",
- "rule",
- "stock",
- "weather",
- "chance",
- "figure",
- "man",
- "model",
- "source",
- "beginning",
- "earth",
- "program",
- "chicken",
- "design",
- "feature",
- "head",
- "material",
- "purpose",
- "question",
- "rock",
- "salt",
- "act",
- "birth",
- "car",
- "dog",
- "object",
- "scale",
- "sun",
- "note",
- "profit",
- "rent",
- "speed",
- "style",
- "war",
- "bank",
- "craft",
- "half",
- "inside",
- "outside",
- "standard",
- "bus",
- "exchange",
- "eye",
- "fire",
- "position",
- "pressure",
- "stress",
- "advantage",
- "benefit",
- "box",
- "frame",
- "issue",
- "step",
- "cycle",
- "face",
- "item",
- "metal",
- "paint",
- "review",
- "room",
- "screen",
- "structure",
- "view",
- "account",
- "ball",
- "discipline",
- "medium",
- "share",
- "balance",
- "bit",
- "black",
- "bottom",
- "choice",
- "gift",
- "impact",
- "machine",
- "shape",
- "tool",
- "wind",
- "address",
- "average",
- "career",
- "culture",
- "morning",
- "pot",
- "sign",
- "table",
- "task",
- "condition",
- "contact",
- "credit",
- "egg",
- "hope",
- "ice",
- "network",
- "north",
- "square",
- "attempt",
- "date",
- "effect",
- "link",
- "post",
- "star",
- "voice",
- "capital",
- "challenge",
- "friend",
- "self",
- "shot",
- "brush",
- "couple",
- "debate",
- "exit",
- "front",
- "function",
- "lack",
- "living",
- "plant",
- "plastic",
- "spot",
- "summer",
- "taste",
- "theme",
- "track",
- "wing",
- "brain",
- "button",
- "click",
- "desire",
- "foot",
- "gas",
- "influence",
- "notice",
- "rain",
- "wall",
- "base",
- "damage",
- "distance",
- "feeling",
- "pair",
- "savings",
- "staff",
- "sugar",
- "target",
- "text",
- "animal",
- "author",
- "budget",
- "discount",
- "file",
- "ground",
- "lesson",
- "minute",
- "officer",
- "phase",
- "reference",
- "register",
- "sky",
- "stage",
- "stick",
- "title",
- "trouble",
- "bowl",
- "bridge",
- "campaign",
- "character",
- "club",
- "edge",
- "evidence",
- "fan",
- "letter",
- "lock",
- "maximum",
- "novel",
- "option",
- "pack",
- "park",
- "plenty",
- "quarter",
- "skin",
- "sort",
- "weight",
- "baby",
- "background",
- "carry",
- "dish",
- "factor",
- "fruit",
- "glass",
- "joint",
- "master",
- "muscle",
- "red",
- "strength",
- "traffic",
- "trip",
- "vegetable",
- "appeal",
- "chart",
- "gear",
- "ideal",
- "kitchen",
- "land",
- "log",
- "mother",
- "net",
- "party",
- "principle",
- "relative",
- "sale",
- "season",
- "signal",
- "spirit",
- "street",
- "tree",
- "wave",
- "belt",
- "bench",
- "commission",
- "copy",
- "drop",
- "minimum",
- "path",
- "progress",
- "project",
- "sea",
- "south",
- "status",
- "stuff",
- "ticket",
- "tour",
- "angle",
- "blue",
- "breakfast",
- "confidence",
- "daughter",
- "degree",
- "doctor",
- "dot",
- "dream",
- "duty",
- "essay",
- "father",
- "fee",
- "finance",
- "hour",
- "juice",
- "limit",
- "luck",
- "milk",
- "mouth",
- "peace",
- "pipe",
- "seat",
- "stable",
- "storm",
- "substance",
- "team",
- "trick",
- "afternoon",
- "bat",
- "beach",
- "blank",
- "catch",
- "chain",
- "consideration",
- "cream",
- "crew",
- "detail",
- "gold",
- "interview",
- "kid",
- "mark",
- "match",
- "mission",
- "pain",
- "pleasure",
- "score",
- "screw",
- "sex",
- "shop",
- "shower",
- "suit",
- "tone",
- "window",
- "agent",
- "band",
- "block",
- "bone",
- "calendar",
- "cap",
- "coat",
- "contest",
- "corner",
- "court",
- "cup",
- "district",
- "door",
- "east",
- "finger",
- "garage",
- "guarantee",
- "hole",
- "hook",
- "implement",
- "layer",
- "lecture",
- "lie",
- "manner",
- "meeting",
- "nose",
- "parking",
- "partner",
- "profile",
- "respect",
- "rice",
- "routine",
- "schedule",
- "swimming",
- "telephone",
- "tip",
- "winter",
- "airline",
- "bag",
- "battle",
- "bed",
- "bill",
- "bother",
- "cake",
- "code",
- "curve",
- "designer",
- "dimension",
- "dress",
- "ease",
- "emergency",
- "evening",
- "extension",
- "farm",
- "fight",
- "gap",
- "grade",
- "holiday",
- "horror",
- "horse",
- "host",
- "husband",
- "loan",
- "mistake",
- "mountain",
- "nail",
- "noise",
- "occasion",
- "package",
- "patient",
- "pause",
- "phrase",
- "proof",
- "race",
- "relief",
- "sand",
- "sentence",
- "shoulder",
- "smoke",
- "stomach",
- "string",
- "tourist",
- "towel",
- "vacation",
- "west",
- "wheel",
- "wine",
- "arm",
- "aside",
- "associate",
- "bet",
- "blow",
- "border",
- "branch",
- "breast",
- "brother",
- "buddy",
- "bunch",
- "chip",
- "coach",
- "cross",
- "document",
- "draft",
- "dust",
- "expert",
- "floor",
- "god",
- "golf",
- "habit",
- "iron",
- "judge",
- "knife",
- "landscape",
- "league",
- "mail",
- "mess",
- "native",
- "opening",
- "parent",
- "pattern",
- "pin",
- "pool",
- "pound",
- "request",
- "salary",
- "shame",
- "shelter",
- "shoe",
- "silver",
- "tackle",
- "tank",
- "trust",
- "assist",
- "bake",
- "bar",
- "bell",
- "bike",
- "blame",
- "boy",
- "brick",
- "chair",
- "closet",
- "clue",
- "collar",
- "comment",
- "conference",
- "devil",
- "diet",
- "fear",
- "fuel",
- "glove",
- "jacket",
- "lunch",
- "monitor",
- "mortgage",
- "nurse",
- "pace",
- "panic",
- "peak",
- "plane",
- "reward",
- "row",
- "sandwich",
- "shock",
- "spite",
- "spray",
- "surprise",
- "till",
- "transition",
- "weekend",
- "welcome",
- "yard",
- "alarm",
- "bend",
- "bicycle",
- "bite",
- "blind",
- "bottle",
- "cable",
- "candle",
- "clerk",
- "cloud",
- "concert",
- "counter",
- "flower",
- "grandfather",
- "harm",
- "knee",
- "lawyer",
- "leather",
- "load",
- "mirror",
- "neck",
- "pension",
- "plate",
- "purple",
- "ruin",
- "ship",
- "skirt",
- "slice",
- "snow",
- "specialist",
- "stroke",
- "switch",
- "trash",
- "tune",
- "zone",
- "anger",
- "award",
- "bid",
- "bitter",
- "boot",
- "bug",
- "camp",
- "candy",
- "carpet",
- "cat",
- "champion",
- "channel",
- "clock",
- "comfort",
- "cow",
- "crack",
- "engineer",
- "entrance",
- "fault",
- "grass",
- "guy",
- "hell",
- "highlight",
- "incident",
- "island",
- "joke",
- "jury",
- "leg",
- "lip",
- "mate",
- "motor",
- "nerve",
- "passage",
- "pen",
- "pride",
- "priest",
- "prize",
- "promise",
- "resident",
- "resort",
- "ring",
- "roof",
- "rope",
- "sail",
- "scheme",
- "script",
- "sock",
- "station",
- "toe",
- "tower",
- "truck",
- "witness",
- "a",
- "you",
- "it",
- "can",
- "will",
- "if",
- "one",
- "many",
- "most",
- "other",
- "use",
- "make",
- "good",
- "look",
- "help",
- "go",
- "great",
- "being",
- "few",
- "might",
- "still",
- "public",
- "read",
- "keep",
- "start",
- "give",
- "human",
- "local",
- "general",
- "she",
- "specific",
- "long",
- "play",
- "feel",
- "high",
- "tonight",
- "put",
- "common",
- "set",
- "change",
- "simple",
- "past",
- "big",
- "possible",
- "particular",
- "today",
- "major",
- "personal",
- "current",
- "national",
- "cut",
- "natural",
- "physical",
- "show",
- "try",
- "check",
- "second",
- "call",
- "move",
- "pay",
- "let",
- "increase",
- "single",
- "individual",
- "turn",
- "ask",
- "buy",
- "guard",
- "hold",
- "main",
- "offer",
- "potential",
- "professional",
- "international",
- "travel",
- "cook",
- "alternative",
- "following",
- "special",
- "working",
- "whole",
- "dance",
- "excuse",
- "cold",
- "commercial",
- "low",
- "purchase",
- "deal",
- "primary",
- "worth",
- "fall",
- "necessary",
- "positive",
- "produce",
- "search",
- "present",
- "spend",
- "talk",
- "creative",
- "tell",
- "cost",
- "drive",
- "green",
- "support",
- "glad",
- "remove",
- "return",
- "run",
- "complex",
- "due",
- "effective",
- "middle",
- "regular",
- "reserve",
- "independent",
- "leave",
- "original",
- "reach",
- "rest",
- "serve",
- "watch",
- "beautiful",
- "charge",
- "active",
- "break",
- "negative",
- "safe",
- "stay",
- "visit",
- "visual",
- "affect",
- "cover",
- "report",
- "rise",
- "walk",
- "white",
- "beyond",
- "junior",
- "pick",
- "unique",
- "anything",
- "classic",
- "final",
- "lift",
- "mix",
- "private",
- "stop",
- "teach",
- "western",
- "concern",
- "familiar",
- "fly",
- "official",
- "broad",
- "comfortable",
- "gain",
- "maybe",
- "rich",
- "save",
- "stand",
- "young",
- "fail",
- "heavy",
- "hello",
- "lead",
- "listen",
- "valuable",
- "worry",
- "handle",
- "leading",
- "meet",
- "release",
- "sell",
- "finish",
- "normal",
- "press",
- "ride",
- "secret",
- "spread",
- "spring",
- "tough",
- "wait",
- "brown",
- "deep",
- "display",
- "flow",
- "hit",
- "objective",
- "shoot",
- "touch",
- "cancel",
- "chemical",
- "cry",
- "dump",
- "extreme",
- "push",
- "conflict",
- "eat",
- "fill",
- "formal",
- "jump",
- "kick",
- "opposite",
- "pass",
- "pitch",
- "remote",
- "total",
- "treat",
- "vast",
- "abuse",
- "beat",
- "burn",
- "deposit",
- "print",
- "raise",
- "sleep",
- "somewhere",
- "advance",
- "anywhere",
- "consist",
- "dark",
- "double",
- "draw",
- "equal",
- "fix",
- "hire",
- "internal",
- "join",
- "kill",
- "sensitive",
- "tap",
- "win",
- "attack",
- "claim",
- "constant",
- "drag",
- "drink",
- "guess",
- "minor",
- "pull",
- "raw",
- "soft",
- "solid",
- "wear",
- "weird",
- "wonder",
- "annual",
- "count",
- "dead",
- "doubt",
- "feed",
- "forever",
- "impress",
- "nobody",
- "repeat",
- "round",
- "sing",
- "slide",
- "strip",
- "whereas",
- "wish",
- "combine",
- "command",
- "dig",
- "divide",
- "equivalent",
- "hang",
- "hunt",
- "initial",
- "march",
- "mention",
- "smell",
- "spiritual",
- "survey",
- "tie",
- "adult",
- "brief",
- "crazy",
- "escape",
- "gather",
- "hate",
- "prior",
- "repair",
- "rough",
- "sad",
- "scratch",
- "sick",
- "strike",
- "employ",
- "external",
- "hurt",
- "illegal",
- "laugh",
- "lay",
- "mobile",
- "nasty",
- "ordinary",
- "respond",
- "royal",
- "senior",
- "split",
- "strain",
- "struggle",
- "swim",
- "train",
- "upper",
- "wash",
- "yellow",
- "convert",
- "crash",
- "dependent",
- "fold",
- "funny",
- "grab",
- "hide",
- "miss",
- "permit",
- "quote",
- "recover",
- "resolve",
- "roll",
- "sink",
- "slip",
- "spare",
- "suspect",
- "sweet",
- "swing",
- "twist",
- "upstairs",
- "usual",
- "abroad",
- "brave",
- "calm",
- "concentrate",
- "estimate",
- "grand",
- "male",
- "mine",
- "prompt",
- "quiet",
- "refuse",
- "regret",
- "reveal",
- "rush",
- "shake",
- "shift",
- "shine",
- "steal",
- "suck",
- "surround",
- "anybody",
- "bear",
- "brilliant",
- "dare",
- "dear",
- "delay",
- "drunk",
- "female",
- "hurry",
- "inevitable",
- "invite",
- "kiss",
- "neat",
- "pop",
- "punch",
- "quit",
- "reply",
- "representative",
- "resist",
- "rip",
- "rub",
- "silly",
- "smile",
- "spell",
- "stretch",
- "stupid",
- "tear",
- "temporary",
- "tomorrow",
- "wake",
- "wrap",
- "yesterday"
-];
-var adj = [
- "abandoned",
- "able",
- "absolute",
- "adorable",
- "adventurous",
- "academic",
- "acceptable",
- "acclaimed",
- "accomplished",
- "accurate",
- "aching",
- "acidic",
- "acrobatic",
- "active",
- "actual",
- "adept",
- "admirable",
- "admired",
- "adolescent",
- "adorable",
- "adored",
- "advanced",
- "afraid",
- "affectionate",
- "aged",
- "aggravating",
- "aggressive",
- "agile",
- "agitated",
- "agonizing",
- "agreeable",
- "ajar",
- "alarmed",
- "alarming",
- "alert",
- "alienated",
- "alive",
- "all",
- "altruistic",
- "amazing",
- "ambitious",
- "ample",
- "amused",
- "amusing",
- "anchored",
- "ancient",
- "angelic",
- "angry",
- "anguished",
- "animated",
- "annual",
- "another",
- "antique",
- "anxious",
- "any",
- "apprehensive",
- "appropriate",
- "apt",
- "arctic",
- "arid",
- "aromatic",
- "artistic",
- "ashamed",
- "assured",
- "astonishing",
- "athletic",
- "attached",
- "attentive",
- "attractive",
- "austere",
- "authentic",
- "authorized",
- "automatic",
- "avaricious",
- "average",
- "aware",
- "awesome",
- "awful",
- "awkward",
- "babyish",
- "bad",
- "back",
- "baggy",
- "bare",
- "barren",
- "basic",
- "beautiful",
- "belated",
- "beloved",
- "beneficial",
- "better",
- "best",
- "bewitched",
- "big",
- "big-hearted",
- "biodegradable",
- "bite-sized",
- "bitter",
- "black",
- "black-and-white",
- "bland",
- "blank",
- "blaring",
- "bleak",
- "blind",
- "blissful",
- "blond",
- "blue",
- "blushing",
- "bogus",
- "boiling",
- "bold",
- "bony",
- "boring",
- "bossy",
- "both",
- "bouncy",
- "bountiful",
- "bowed",
- "brave",
- "breakable",
- "brief",
- "bright",
- "brilliant",
- "brisk",
- "broken",
- "bronze",
- "brown",
- "bruised",
- "bubbly",
- "bulky",
- "bumpy",
- "buoyant",
- "burdensome",
- "burly",
- "bustling",
- "busy",
- "buttery",
- "buzzing",
- "calculating",
- "calm",
- "candid",
- "canine",
- "capital",
- "carefree",
- "careful",
- "careless",
- "caring",
- "cautious",
- "cavernous",
- "celebrated",
- "charming",
- "cheap",
- "cheerful",
- "cheery",
- "chief",
- "chilly",
- "chubby",
- "circular",
- "classic",
- "clean",
- "clear",
- "clear-cut",
- "clever",
- "close",
- "closed",
- "cloudy",
- "clueless",
- "clumsy",
- "cluttered",
- "coarse",
- "cold",
- "colorful",
- "colorless",
- "colossal",
- "comfortable",
- "common",
- "compassionate",
- "competent",
- "complete",
- "complex",
- "complicated",
- "composed",
- "concerned",
- "concrete",
- "confused",
- "conscious",
- "considerate",
- "constant",
- "content",
- "conventional",
- "cooked",
- "cool",
- "cooperative",
- "coordinated",
- "corny",
- "corrupt",
- "costly",
- "courageous",
- "courteous",
- "crafty",
- "crazy",
- "creamy",
- "creative",
- "creepy",
- "criminal",
- "crisp",
- "critical",
- "crooked",
- "crowded",
- "cruel",
- "crushing",
- "cuddly",
- "cultivated",
- "cultured",
- "cumbersome",
- "curly",
- "curvy",
- "cute",
- "cylindrical",
- "damaged",
- "damp",
- "dangerous",
- "dapper",
- "daring",
- "darling",
- "dark",
- "dazzling",
- "dead",
- "deadly",
- "deafening",
- "dear",
- "dearest",
- "decent",
- "decimal",
- "decisive",
- "deep",
- "defenseless",
- "defensive",
- "defiant",
- "deficient",
- "definite",
- "definitive",
- "delayed",
- "delectable",
- "delicious",
- "delightful",
- "delirious",
- "demanding",
- "dense",
- "dental",
- "dependable",
- "dependent",
- "descriptive",
- "deserted",
- "detailed",
- "determined",
- "devoted",
- "different",
- "difficult",
- "digital",
- "diligent",
- "dim",
- "dimpled",
- "dimwitted",
- "direct",
- "disastrous",
- "discrete",
- "disfigured",
- "disgusting",
- "disloyal",
- "dismal",
- "distant",
- "downright",
- "dreary",
- "dirty",
- "disguised",
- "dishonest",
- "dismal",
- "distant",
- "distinct",
- "distorted",
- "dizzy",
- "dopey",
- "doting",
- "double",
- "downright",
- "drab",
- "drafty",
- "dramatic",
- "dreary",
- "droopy",
- "dry",
- "dual",
- "dull",
- "dutiful",
- "each",
- "eager",
- "earnest",
- "early",
- "easy",
- "easy-going",
- "ecstatic",
- "edible",
- "educated",
- "elaborate",
- "elastic",
- "elated",
- "elderly",
- "electric",
- "elegant",
- "elementary",
- "elliptical",
- "embarrassed",
- "embellished",
- "eminent",
- "emotional",
- "empty",
- "enchanted",
- "enchanting",
- "energetic",
- "enlightened",
- "enormous",
- "enraged",
- "entire",
- "envious",
- "equal",
- "equatorial",
- "essential",
- "esteemed",
- "ethical",
- "euphoric",
- "even",
- "evergreen",
- "everlasting",
- "every",
- "evil",
- "exalted",
- "excellent",
- "exemplary",
- "exhausted",
- "excitable",
- "excited",
- "exciting",
- "exotic",
- "expensive",
- "experienced",
- "expert",
- "extraneous",
- "extroverted",
- "extra-large",
- "extra-small",
- "fabulous",
- "failing",
- "faint",
- "fair",
- "faithful",
- "fake",
- "false",
- "familiar",
- "famous",
- "fancy",
- "fantastic",
- "far",
- "faraway",
- "far-flung",
- "far-off",
- "fast",
- "fat",
- "fatal",
- "fatherly",
- "favorable",
- "favorite",
- "fearful",
- "fearless",
- "feisty",
- "feline",
- "female",
- "feminine",
- "few",
- "fickle",
- "filthy",
- "fine",
- "finished",
- "firm",
- "first",
- "firsthand",
- "fitting",
- "fixed",
- "flaky",
- "flamboyant",
- "flashy",
- "flat",
- "flawed",
- "flawless",
- "flickering",
- "flimsy",
- "flippant",
- "flowery",
- "fluffy",
- "fluid",
- "flustered",
- "focused",
- "fond",
- "foolhardy",
- "foolish",
- "forceful",
- "forked",
- "formal",
- "forsaken",
- "forthright",
- "fortunate",
- "fragrant",
- "frail",
- "frank",
- "frayed",
- "free",
- "French",
- "fresh",
- "frequent",
- "friendly",
- "frightened",
- "frightening",
- "frigid",
- "frilly",
- "frizzy",
- "frivolous",
- "front",
- "frosty",
- "frozen",
- "frugal",
- "fruitful",
- "full",
- "fumbling",
- "functional",
- "funny",
- "fussy",
- "fuzzy",
- "gargantuan",
- "gaseous",
- "general",
- "generous",
- "gentle",
- "genuine",
- "giant",
- "giddy",
- "gigantic",
- "gifted",
- "giving",
- "glamorous",
- "glaring",
- "glass",
- "gleaming",
- "gleeful",
- "glistening",
- "glittering",
- "gloomy",
- "glorious",
- "glossy",
- "glum",
- "golden",
- "good",
- "good-natured",
- "gorgeous",
- "graceful",
- "gracious",
- "grand",
- "grandiose",
- "granular",
- "grateful",
- "grave",
- "gray",
- "great",
- "greedy",
- "green",
- "gregarious",
- "grim",
- "grimy",
- "gripping",
- "grizzled",
- "gross",
- "grotesque",
- "grouchy",
- "grounded",
- "growing",
- "growling",
- "grown",
- "grubby",
- "gruesome",
- "grumpy",
- "guilty",
- "gullible",
- "gummy",
- "hairy",
- "half",
- "handmade",
- "handsome",
- "handy",
- "happy",
- "happy-go-lucky",
- "hard",
- "hard-to-find",
- "harmful",
- "harmless",
- "harmonious",
- "harsh",
- "hasty",
- "hateful",
- "haunting",
- "healthy",
- "heartfelt",
- "hearty",
- "heavenly",
- "heavy",
- "hefty",
- "helpful",
- "helpless",
- "hidden",
- "hideous",
- "high",
- "high-level",
- "hilarious",
- "hoarse",
- "hollow",
- "homely",
- "honest",
- "honorable",
- "honored",
- "hopeful",
- "horrible",
- "hospitable",
- "hot",
- "huge",
- "humble",
- "humiliating",
- "humming",
- "humongous",
- "hungry",
- "hurtful",
- "husky",
- "icky",
- "icy",
- "ideal",
- "idealistic",
- "identical",
- "idle",
- "idiotic",
- "idolized",
- "ignorant",
- "ill",
- "illegal",
- "ill-fated",
- "ill-informed",
- "illiterate",
- "illustrious",
- "imaginary",
- "imaginative",
- "immaculate",
- "immaterial",
- "immediate",
- "immense",
- "impassioned",
- "impeccable",
- "impartial",
- "imperfect",
- "imperturbable",
- "impish",
- "impolite",
- "important",
- "impossible",
- "impractical",
- "impressionable",
- "impressive",
- "improbable",
- "impure",
- "inborn",
- "incomparable",
- "incompatible",
- "incomplete",
- "inconsequential",
- "incredible",
- "indelible",
- "inexperienced",
- "indolent",
- "infamous",
- "infantile",
- "infatuated",
- "inferior",
- "infinite",
- "informal",
- "innocent",
- "insecure",
- "insidious",
- "insignificant",
- "insistent",
- "instructive",
- "insubstantial",
- "intelligent",
- "intent",
- "intentional",
- "interesting",
- "internal",
- "international",
- "intrepid",
- "ironclad",
- "irresponsible",
- "irritating",
- "itchy",
- "jaded",
- "jagged",
- "jam-packed",
- "jaunty",
- "jealous",
- "jittery",
- "joint",
- "jolly",
- "jovial",
- "joyful",
- "joyous",
- "jubilant",
- "judicious",
- "juicy",
- "jumbo",
- "junior",
- "jumpy",
- "juvenile",
- "kaleidoscopic",
- "keen",
- "key",
- "kind",
- "kindhearted",
- "kindly",
- "klutzy",
- "knobby",
- "knotty",
- "knowledgeable",
- "knowing",
- "known",
- "kooky",
- "kosher",
- "lame",
- "lanky",
- "large",
- "last",
- "lasting",
- "late",
- "lavish",
- "lawful",
- "lazy",
- "leading",
- "lean",
- "leafy",
- "left",
- "legal",
- "legitimate",
- "light",
- "lighthearted",
- "likable",
- "likely",
- "limited",
- "limp",
- "limping",
- "linear",
- "lined",
- "liquid",
- "little",
- "live",
- "lively",
- "livid",
- "loathsome",
- "lone",
- "lonely",
- "long",
- "long-term",
- "loose",
- "lopsided",
- "lost",
- "loud",
- "lovable",
- "lovely",
- "loving",
- "low",
- "loyal",
- "lucky",
- "lumbering",
- "luminous",
- "lumpy",
- "lustrous",
- "luxurious",
- "mad",
- "made-up",
- "magnificent",
- "majestic",
- "major",
- "male",
- "mammoth",
- "married",
- "marvelous",
- "masculine",
- "massive",
- "mature",
- "meager",
- "mealy",
- "mean",
- "measly",
- "meaty",
- "medical",
- "mediocre",
- "medium",
- "meek",
- "mellow",
- "melodic",
- "memorable",
- "menacing",
- "merry",
- "messy",
- "metallic",
- "mild",
- "milky",
- "mindless",
- "miniature",
- "minor",
- "minty",
- "miserable",
- "miserly",
- "misguided",
- "misty",
- "mixed",
- "modern",
- "modest",
- "moist",
- "monstrous",
- "monthly",
- "monumental",
- "moral",
- "mortified",
- "motherly",
- "motionless",
- "mountainous",
- "muddy",
- "muffled",
- "multicolored",
- "mundane",
- "murky",
- "mushy",
- "musty",
- "muted",
- "mysterious",
- "naive",
- "narrow",
- "nasty",
- "natural",
- "naughty",
- "nautical",
- "near",
- "neat",
- "necessary",
- "needy",
- "negative",
- "neglected",
- "negligible",
- "neighboring",
- "nervous",
- "new",
- "next",
- "nice",
- "nifty",
- "nimble",
- "nippy",
- "nocturnal",
- "noisy",
- "nonstop",
- "normal",
- "notable",
- "noted",
- "noteworthy",
- "novel",
- "noxious",
- "numb",
- "nutritious",
- "nutty",
- "obedient",
- "obese",
- "oblong",
- "oily",
- "oblong",
- "obvious",
- "occasional",
- "odd",
- "oddball",
- "offbeat",
- "offensive",
- "official",
- "old",
- "old-fashioned",
- "only",
- "open",
- "optimal",
- "optimistic",
- "opulent",
- "orange",
- "orderly",
- "organic",
- "ornate",
- "ornery",
- "ordinary",
- "original",
- "other",
- "our",
- "outlying",
- "outgoing",
- "outlandish",
- "outrageous",
- "outstanding",
- "oval",
- "overcooked",
- "overdue",
- "overjoyed",
- "overlooked",
- "palatable",
- "pale",
- "paltry",
- "parallel",
- "parched",
- "partial",
- "passionate",
- "past",
- "pastel",
- "peaceful",
- "peppery",
- "perfect",
- "perfumed",
- "periodic",
- "perky",
- "personal",
- "pertinent",
- "pesky",
- "pessimistic",
- "petty",
- "phony",
- "physical",
- "piercing",
- "pink",
- "pitiful",
- "plain",
- "plaintive",
- "plastic",
- "playful",
- "pleasant",
- "pleased",
- "pleasing",
- "plump",
- "plush",
- "polished",
- "polite",
- "political",
- "pointed",
- "pointless",
- "poised",
- "poor",
- "popular",
- "portly",
- "posh",
- "positive",
- "possible",
- "potable",
- "powerful",
- "powerless",
- "practical",
- "precious",
- "present",
- "prestigious",
- "pretty",
- "precious",
- "previous",
- "pricey",
- "prickly",
- "primary",
- "prime",
- "pristine",
- "private",
- "prize",
- "probable",
- "productive",
- "profitable",
- "profuse",
- "proper",
- "proud",
- "prudent",
- "punctual",
- "pungent",
- "puny",
- "pure",
- "purple",
- "pushy",
- "putrid",
- "puzzled",
- "puzzling",
- "quaint",
- "qualified",
- "quarrelsome",
- "quarterly",
- "queasy",
- "querulous",
- "questionable",
- "quick",
- "quick-witted",
- "quiet",
- "quintessential",
- "quirky",
- "quixotic",
- "quizzical",
- "radiant",
- "ragged",
- "rapid",
- "rare",
- "rash",
- "raw",
- "recent",
- "reckless",
- "rectangular",
- "ready",
- "real",
- "realistic",
- "reasonable",
- "red",
- "reflecting",
- "regal",
- "regular",
- "reliable",
- "relieved",
- "remarkable",
- "remorseful",
- "remote",
- "repentant",
- "required",
- "respectful",
- "responsible",
- "repulsive",
- "revolving",
- "rewarding",
- "rich",
- "rigid",
- "right",
- "ringed",
- "ripe",
- "roasted",
- "robust",
- "rosy",
- "rotating",
- "rotten",
- "rough",
- "round",
- "rowdy",
- "royal",
- "rubbery",
- "rundown",
- "ruddy",
- "rude",
- "runny",
- "rural",
- "rusty",
- "sad",
- "safe",
- "salty",
- "same",
- "sandy",
- "sane",
- "sarcastic",
- "sardonic",
- "satisfied",
- "scaly",
- "scarce",
- "scared",
- "scary",
- "scented",
- "scholarly",
- "scientific",
- "scornful",
- "scratchy",
- "scrawny",
- "second",
- "secondary",
- "second-hand",
- "secret",
- "self-assured",
- "self-reliant",
- "selfish",
- "sentimental",
- "separate",
- "serene",
- "serious",
- "serpentine",
- "several",
- "severe",
- "shabby",
- "shadowy",
- "shady",
- "shallow",
- "shameful",
- "shameless",
- "sharp",
- "shimmering",
- "shiny",
- "shocked",
- "shocking",
- "shoddy",
- "short",
- "short-term",
- "showy",
- "shrill",
- "shy",
- "sick",
- "silent",
- "silky",
- "silly",
- "silver",
- "similar",
- "simple",
- "simplistic",
- "sinful",
- "single",
- "sizzling",
- "skeletal",
- "skinny",
- "sleepy",
- "slight",
- "slim",
- "slimy",
- "slippery",
- "slow",
- "slushy",
- "small",
- "smart",
- "smoggy",
- "smooth",
- "smug",
- "snappy",
- "snarling",
- "sneaky",
- "sniveling",
- "snoopy",
- "sociable",
- "soft",
- "soggy",
- "solid",
- "somber",
- "some",
- "spherical",
- "sophisticated",
- "sore",
- "sorrowful",
- "soulful",
- "soupy",
- "sour",
- "Spanish",
- "sparkling",
- "sparse",
- "specific",
- "spectacular",
- "speedy",
- "spicy",
- "spiffy",
- "spirited",
- "spiteful",
- "splendid",
- "spotless",
- "spotted",
- "spry",
- "square",
- "squeaky",
- "squiggly",
- "stable",
- "staid",
- "stained",
- "stale",
- "standard",
- "starchy",
- "stark",
- "starry",
- "steep",
- "sticky",
- "stiff",
- "stimulating",
- "stingy",
- "stormy",
- "straight",
- "strange",
- "steel",
- "strict",
- "strident",
- "striking",
- "striped",
- "strong",
- "studious",
- "stunning",
- "stupendous",
- "stupid",
- "sturdy",
- "stylish",
- "subdued",
- "submissive",
- "substantial",
- "subtle",
- "suburban",
- "sudden",
- "sugary",
- "sunny",
- "super",
- "superb",
- "superficial",
- "superior",
- "supportive",
- "sure-footed",
- "surprised",
- "suspicious",
- "svelte",
- "sweaty",
- "sweet",
- "sweltering",
- "swift",
- "sympathetic",
- "tall",
- "talkative",
- "tame",
- "tan",
- "tangible",
- "tart",
- "tasty",
- "tattered",
- "taut",
- "tedious",
- "teeming",
- "tempting",
- "tender",
- "tense",
- "tepid",
- "terrible",
- "terrific",
- "testy",
- "thankful",
- "that",
- "these",
- "thick",
- "thin",
- "third",
- "thirsty",
- "this",
- "thorough",
- "thorny",
- "those",
- "thoughtful",
- "threadbare",
- "thrifty",
- "thunderous",
- "tidy",
- "tight",
- "timely",
- "tinted",
- "tiny",
- "tired",
- "torn",
- "total",
- "tough",
- "traumatic",
- "treasured",
- "tremendous",
- "tragic",
- "trained",
- "tremendous",
- "triangular",
- "tricky",
- "trifling",
- "trim",
- "trivial",
- "troubled",
- "true",
- "trusting",
- "trustworthy",
- "trusty",
- "truthful",
- "tubby",
- "turbulent",
- "twin",
- "ugly",
- "ultimate",
- "unacceptable",
- "unaware",
- "uncomfortable",
- "uncommon",
- "unconscious",
- "understated",
- "unequaled",
- "uneven",
- "unfinished",
- "unfit",
- "unfolded",
- "unfortunate",
- "unhappy",
- "unhealthy",
- "uniform",
- "unimportant",
- "unique",
- "united",
- "unkempt",
- "unknown",
- "unlawful",
- "unlined",
- "unlucky",
- "unnatural",
- "unpleasant",
- "unrealistic",
- "unripe",
- "unruly",
- "unselfish",
- "unsightly",
- "unsteady",
- "unsung",
- "untidy",
- "untimely",
- "untried",
- "untrue",
- "unused",
- "unusual",
- "unwelcome",
- "unwieldy",
- "unwilling",
- "unwitting",
- "unwritten",
- "upbeat",
- "upright",
- "upset",
- "urban",
- "usable",
- "used",
- "useful",
- "useless",
- "utilized",
- "utter",
- "vacant",
- "vague",
- "vain",
- "valid",
- "valuable",
- "vapid",
- "variable",
- "vast",
- "velvety",
- "venerated",
- "vengeful",
- "verifiable",
- "vibrant",
- "vicious",
- "victorious",
- "vigilant",
- "vigorous",
- "villainous",
- "violet",
- "violent",
- "virtual",
- "virtuous",
- "visible",
- "vital",
- "vivacious",
- "vivid",
- "voluminous",
- "wan",
- "warlike",
- "warm",
- "warmhearted",
- "warped",
- "wary",
- "wasteful",
- "watchful",
- "waterlogged",
- "watery",
- "wavy",
- "wealthy",
- "weak",
- "weary",
- "webbed",
- "weed",
- "weekly",
- "weepy",
- "weighty",
- "weird",
- "welcome",
- "well-documented",
- "well-groomed",
- "well-informed",
- "well-lit",
- "well-made",
- "well-off",
- "well-to-do",
- "well-worn",
- "wet",
- "which",
- "whimsical",
- "whirlwind",
- "whispered",
- "white",
- "whole",
- "whopping",
- "wicked",
- "wide",
- "wide-eyed",
- "wiggly",
- "wild",
- "willing",
- "wilted",
- "winding",
- "windy",
- "winged",
- "wiry",
- "wise",
- "witty",
- "wobbly",
- "woeful",
- "wonderful",
- "wooden",
- "woozy",
- "wordy",
- "worldly",
- "worn",
- "worried",
- "worrisome",
- "worse",
- "worst",
- "worthless",
- "worthwhile",
- "worthy",
- "wrathful",
- "wretched",
- "writhing",
- "wrong",
- "wry",
- "yawning",
- "yearly",
- "yellow",
- "yellowish",
- "young",
- "youthful",
- "yummy",
- "zany",
- "zealous",
- "zesty",
- "zigzag"
-];
-function getRandomUsername() {
- const n2 = Math.floor(Math.random() * noun.length);
- const a5 = Math.floor(Math.random() * adj.length);
- return {
- first: adj[a5],
- second: noun[n2]
- };
-}
-function getRandomPassword() {
- return encodeCrock(getRandomBytes(16));
+function ShowNotifications() {
+ const ns = useNotifications();
+ if (!ns.length) {
+ return /* @__PURE__ */ h("div", null, "no notifications");
+ }
+ return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("p", null, "Notifications"), /* @__PURE__ */ h("table", null, /* @__PURE__ */ h("thead", null), /* @__PURE__ */ h("tbody", null, ns.map((n2, idx) => {
+ return /* @__PURE__ */ h("tr", { key: idx }, /* @__PURE__ */ h("td", null, /* @__PURE__ */ h(
+ Time,
+ {
+ timestamp: n2.message.when,
+ format: "dd/MM/yyyy HH:mm:ss"
+ }
+ )), /* @__PURE__ */ h("td", null, n2.message.title), /* @__PURE__ */ h("td", null, n2.message.type === "error" ? n2.message.description : void 0));
+ }))));
}
-// src/pages/RegistrationPage.tsx
-function RegistrationPage({
- onRegistrationSuccesful,
- routeCancel
-}) {
- const { i18n: i18n2 } = useTranslationContext();
- const { config } = useBankCoreApiContext();
- if (!config.allow_registrations) {
- return /* @__PURE__ */ h("p", null, i18n2.str`Currently, the bank is not accepting new registrations!`);
- }
- return /* @__PURE__ */ h(
- RegistrationForm,
- {
- onRegistrationSuccesful,
- routeCancel
- }
+// src/pages/SolveChallengePage.tsx
+init_preact_module();
+init_hooks_module();
+
+// src/hooks/regional.ts
+init_hooks_module();
+var useSWR3 = useSWR;
+function revalidateConversionInfo() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getConversionInfoAPI"
);
}
-var USERNAME_REGEX2 = /^[a-z][a-zA-Z0-9-]*$/;
-function RegistrationForm({
- onRegistrationSuccesful,
- routeCancel
-}) {
- const [username, setUsername] = p3();
- const [name, setName] = p3();
- const [password, setPassword] = p3();
- const [repeatPassword, setRepeatPassword] = p3();
- const [notification, _3, handleError] = useLocalNotification();
- const settings = useSettingsContext();
- const { api } = useBankCoreApiContext();
- const { i18n: i18n2 } = useTranslationContext();
- const errors2 = undefinedIfEmpty({
- name: !name ? i18n2.str`Missing name` : void 0,
- username: !username ? i18n2.str`Missing username` : !USERNAME_REGEX2.test(username) ? i18n2.str`Use letters and numbers only, and start with a lowercase letter` : void 0,
- // phone: !phone
- // ? undefined
- // : !PHONE_REGEX.test(phone)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- // : undefined,
- // email: !email
- // ? undefined
- // : !EMAIL_REGEX.test(email)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- // : undefined,
- password: !password ? i18n2.str`Missing password` : void 0,
- repeatPassword: !repeatPassword ? i18n2.str`Missing password` : repeatPassword !== password ? i18n2.str`Passwords don't match` : void 0
+function useConversionInfo() {
+ const { lib: { conversion }, config } = useBankCoreApiContext();
+ async function fetcher() {
+ return await conversion.getConfig();
+ }
+ const { data, error: error2 } = useSWR3(!config.allow_conversion ? void 0 : ["getConversionInfoAPI"], fetcher, {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
});
- async function doRegistrationAndLogin(name2, username2, password2, onComplete) {
- await handleError(async (onError) => {
- const resp = await api.createAccount("", {
- name: name2,
- username: username2,
- password: password2
+ if (data)
+ return data;
+ if (error2)
+ return error2;
+ return void 0;
+}
+function useCashinEstimator() {
+ const { lib: { conversion } } = useBankCoreApiContext();
+ return {
+ estimateByCredit: async (fiatAmount, fee) => {
+ const resp = await conversion.getCashinRate({
+ credit: fiatAmount
});
- if (resp.type === "ok") {
- onComplete();
- } else {
- onError(resp, (_case) => {
- switch (_case) {
- case HttpStatusCode.BadRequest:
- return i18n2.str`Server replied with invalid phone or email.`;
- case HttpStatusCode.Unauthorized:
- return i18n2.str`No enough permission to create that account.`;
- case TalerErrorCode.BANK_UNALLOWED_DEBIT:
- return i18n2.str`Registration is disabled because the bank ran out of bonus credit.`;
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
- return i18n2.str`That username can't be used because is reserved.`;
- case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
- return i18n2.str`That username is already taken.`;
- case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
- return i18n2.str`That account id is already taken.`;
- case TalerErrorCode.BANK_MISSING_TAN_INFO:
- return i18n2.str`No information for the selected authentication channel.`;
- case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
- return i18n2.str`Authentication channel is not supported.`;
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
- return i18n2.str`Only admin is allow to set debt limit.`;
- case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
- return i18n2.str`Only admin can create accounts with second factor authentication.`;
+ if (resp.type === "fail") {
+ switch (resp.case) {
+ case HttpStatusCode.Conflict: {
+ return "amount-is-too-small";
}
- });
+ case HttpStatusCode.NotImplemented:
+ case HttpStatusCode.BadRequest:
+ throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
+ }
}
- });
- }
- async function doRegistrationStep() {
- if (!username || !password || !name)
- return;
- await doRegistrationAndLogin(name, username, password, () => {
- setUsername(void 0);
- setPassword(void 0);
- setRepeatPassword(void 0);
- onRegistrationSuccesful(username, password);
- });
- }
- async function doRandomRegistration() {
- const user = getRandomUsername();
- const password2 = settings.simplePasswordForRandomAccounts ? "123" : getRandomPassword();
- const username2 = `_${user.first}-${user.second}_`;
- const name2 = `${capitalizeFirstLetter(user.first)} ${capitalizeFirstLetter(
- user.second
- )}`;
- await doRegistrationAndLogin(name2, username2, password2, () => {
- onRegistrationSuccesful(username2, password2);
- });
- }
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "flex min-h-full flex-col justify-center" }, /* @__PURE__ */ h("div", { class: "sm:mx-auto sm:w-full sm:max-w-sm" }, /* @__PURE__ */ h("h2", { class: "text-center text-2xl font-bold leading-9 tracking-tight text-gray-900" }, i18n2.str`Account registration`)), /* @__PURE__ */ h("div", { class: "mt-10 sm:mx-auto sm:w-full sm:max-w-sm" }, /* @__PURE__ */ h(
- "form",
- {
- class: "space-y-6",
- noValidate: true,
- onSubmit: (e4) => {
- e4.preventDefault();
- },
- autoCapitalize: "none",
- autoCorrect: "off"
+ const credit = Amounts.parseOrThrow(resp.body.amount_credit);
+ const debit = Amounts.parseOrThrow(resp.body.amount_debit);
+ const beforeFee = Amounts.sub(credit, fee).amount;
+ return {
+ debit,
+ beforeFee,
+ credit
+ };
},
- /* @__PURE__ */ h("div", null, /* @__PURE__ */ h(
- "label",
- {
- for: "username",
- class: "block text-sm font-medium leading-6 text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Login username"),
- /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
- ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
- "input",
- {
- autoFocus: true,
- type: "text",
- name: "username",
- id: "username",
- class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
- value: username ?? "",
- enterkeyhint: "next",
- placeholder: "account identification to login",
- autocomplete: "username",
- required: true,
- onInput: (e4) => {
- setUsername(e4.currentTarget.value);
+ estimateByDebit: async (regionalAmount, fee) => {
+ const resp = await conversion.getCashinRate({
+ debit: regionalAmount
+ });
+ if (resp.type === "fail") {
+ switch (resp.case) {
+ case HttpStatusCode.Conflict: {
+ return "amount-is-too-small";
+ }
+ case HttpStatusCode.NotImplemented:
+ case HttpStatusCode.BadRequest:
+ throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
}
}
- ), /* @__PURE__ */ h(
- ShowInputErrorLabel,
- {
- message: errors2?.username,
- isDirty: username !== void 0
- }
- ))),
- /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h(
- "label",
- {
- for: "password",
- class: "block text-sm font-medium leading-6 text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Password"),
- /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
- )), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
- "input",
- {
- type: "password",
- name: "password",
- id: "password",
- autocomplete: "current-password",
- class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
- enterkeyhint: "send",
- value: password ?? "",
- placeholder: "Password",
- required: true,
- onInput: (e4) => {
- setPassword(e4.currentTarget.value);
+ const credit = Amounts.parseOrThrow(resp.body.amount_credit);
+ const debit = Amounts.parseOrThrow(resp.body.amount_debit);
+ const beforeFee = Amounts.add(credit, fee).amount;
+ return {
+ debit,
+ beforeFee,
+ credit
+ };
+ }
+ };
+}
+function useCashoutEstimator() {
+ const { lib: { conversion } } = useBankCoreApiContext();
+ return {
+ estimateByCredit: async (fiatAmount, fee) => {
+ const resp = await conversion.getCashoutRate({
+ credit: fiatAmount
+ });
+ if (resp.type === "fail") {
+ switch (resp.case) {
+ case HttpStatusCode.Conflict: {
+ return "amount-is-too-small";
+ }
+ case HttpStatusCode.NotImplemented:
+ case HttpStatusCode.BadRequest:
+ throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
}
}
- ), /* @__PURE__ */ h(
- ShowInputErrorLabel,
- {
- message: errors2?.password,
- isDirty: password !== void 0
- }
- ))),
- /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h(
- "label",
- {
- for: "register-repeat",
- class: "block text-sm font-medium leading-6 text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Repeat password"),
- /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
- )), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
- "input",
- {
- type: "password",
- name: "register-repeat",
- id: "register-repeat",
- autocomplete: "current-password",
- class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
- enterkeyhint: "send",
- value: repeatPassword ?? "",
- placeholder: "Same password",
- required: true,
- onInput: (e4) => {
- setRepeatPassword(e4.currentTarget.value);
+ const credit = Amounts.parseOrThrow(resp.body.amount_credit);
+ const debit = Amounts.parseOrThrow(resp.body.amount_debit);
+ const beforeFee = Amounts.sub(credit, fee).amount;
+ return {
+ debit,
+ beforeFee,
+ credit
+ };
+ },
+ estimateByDebit: async (regionalAmount, fee) => {
+ const resp = await conversion.getCashoutRate({
+ debit: regionalAmount
+ });
+ if (resp.type === "fail") {
+ switch (resp.case) {
+ case HttpStatusCode.Conflict: {
+ return "amount-is-too-small";
+ }
+ case HttpStatusCode.NotImplemented:
+ case HttpStatusCode.BadRequest:
+ throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
}
}
- ), /* @__PURE__ */ h(
- ShowInputErrorLabel,
- {
- message: errors2?.repeatPassword,
- isDirty: repeatPassword !== void 0
- }
- ))),
- /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h(
- "label",
- {
- for: "name",
- class: "block text-sm font-medium leading-6 text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Full name"),
- /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
- )), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
- "input",
+ const credit = Amounts.parseOrThrow(resp.body.amount_credit);
+ const debit = Amounts.parseOrThrow(resp.body.amount_debit);
+ const beforeFee = Amounts.add(credit, fee).amount;
+ return {
+ debit,
+ beforeFee,
+ credit
+ };
+ }
+ };
+}
+async function revalidateBusinessAccounts() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getAccounts",
+ void 0,
+ { revalidate: true }
+ );
+}
+function useBusinessAccounts() {
+ const { state: credentials } = useSessionState();
+ const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ const [offset, setOffset] = p3();
+ function fetcher([token2, offset2]) {
+ return api.getAccounts(
+ token2,
+ {},
{
- autoFocus: true,
- type: "text",
- name: "name",
- id: "name",
- class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
- value: name ?? "",
- enterkeyhint: "next",
- placeholder: "John Doe",
- autocomplete: "name",
- required: true,
- onInput: (e4) => {
- setName(e4.currentTarget.value);
- }
+ limit: PAGE_SIZE + 1,
+ offset: String(offset2),
+ order: "asc"
}
- ))),
- /* @__PURE__ */ h("div", { class: "flex w-full justify-between" }, /* @__PURE__ */ h(
- "a",
- {
- name: "cancel",
- href: routeCancel.url({}),
- class: "ring-1 ring-gray-600 rounded-md bg-white disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-white-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")
- ), /* @__PURE__ */ h(
- "button",
- {
- type: "submit",
- name: "register",
- class: " rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
- disabled: !!errors2,
- onClick: async (e4) => {
- e4.preventDefault();
- doRegistrationStep();
+ );
+ }
+ const { data, error: error2 } = useSWR3([token, offset ?? 0, "getAccounts"], fetcher, {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
+ });
+ const isLastPage = data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE;
+ const isFirstPage = !offset;
+ const result = data && data.type == "ok" ? structuredClone(data.body.accounts) : [];
+ if (result.length == PAGE_SIZE + 1) {
+ result.pop();
+ }
+ const pagination = {
+ result,
+ isLastPage,
+ isFirstPage,
+ loadNext: () => {
+ if (!result.length)
+ return;
+ setOffset(result[result.length - 1].row_id);
+ },
+ loadFirst: () => {
+ setOffset(0);
+ }
+ };
+ if (data)
+ return { ok: true, data, ...pagination };
+ if (error2)
+ return error2;
+ return void 0;
+}
+function notUndefined(c4) {
+ return c4 !== void 0;
+}
+function revalidateCashouts() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "useCashouts"
+ );
+}
+function useCashouts(account) {
+ const { state: credentials } = useSessionState();
+ const { lib: { bank: api }, config } = useBankCoreApiContext();
+ const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
+ async function fetcher([username, token2]) {
+ const list = await api.getAccountCashouts({ username, token: token2 });
+ if (list.type !== "ok") {
+ return list;
+ }
+ const all = await Promise.all(
+ list.body.cashouts.map(async (c4) => {
+ const r3 = await api.getCashoutById({ username, token: token2 }, c4.cashout_id);
+ if (r3.type === "fail") {
+ return void 0;
}
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Register")
- ))
- ), settings.allowRandomAccountCreation && /* @__PURE__ */ h("p", { class: "mt-10 text-center text-sm text-gray-500 border-t" }, /* @__PURE__ */ h(
- "button",
+ return { ...r3.body, id: c4.cashout_id };
+ })
+ );
+ const cashouts = all.filter(notUndefined);
+ return { type: "ok", body: { cashouts } };
+ }
+ const { data, error: error2 } = useSWR3(
+ !config.allow_conversion ? void 0 : [account, token, "useCashouts"],
+ fetcher,
{
- type: "submit",
- name: "create random",
- class: "flex mt-4 w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600",
- onClick: (e4) => {
- e4.preventDefault();
- doRandomRegistration();
- }
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Create a random temporary user")
- )))));
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
+ }
+ );
+ if (data)
+ return data;
+ if (error2)
+ return error2;
+ return void 0;
}
-function capitalizeFirstLetter(str) {
- return str.charAt(0).toUpperCase() + str.slice(1);
+function useCashoutDetails(cashoutId) {
+ const { state: credentials } = useSessionState();
+ const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ async function fetcher([username, token, id]) {
+ return api.getCashoutById({ username, token }, id);
+ }
+ const { data, error: error2 } = useSWR3(
+ cashoutId === void 0 ? void 0 : [creds?.username, creds?.token, cashoutId, "getCashoutById"],
+ fetcher,
+ {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
+ }
+ );
+ if (data)
+ return data;
+ if (error2)
+ return error2;
+ return void 0;
+}
+function useLastMonitorInfo(currentMoment, previousMoment, timeframe) {
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ const { state: credentials } = useSessionState();
+ const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
+ async function fetcher([token2, timeframe2]) {
+ const [current, previous] = await Promise.all([
+ api.getMonitor(token2, { timeframe: timeframe2, which: currentMoment }),
+ api.getMonitor(token2, { timeframe: timeframe2, which: previousMoment })
+ ]);
+ return {
+ current,
+ previous
+ };
+ }
+ const { data, error: error2 } = useSWR3(
+ !token ? void 0 : [token, timeframe, "useLastMonitorInfo"],
+ fetcher,
+ {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true
+ }
+ );
+ if (data)
+ return data;
+ if (error2)
+ return error2;
+ return void 0;
}
-
-// src/pages/SolveChallengePage.tsx
-init_preact_module();
-init_hooks_module();
// src/pages/WithdrawalQRCode.tsx
init_preact_module();
@@ -33882,21 +33008,18 @@ function QrCodeSection({
const { i18n: i18n2 } = useTranslationContext();
const walletInegrationApi = useTalerWalletIntegrationAPI();
const talerWithdrawUri = stringifyWithdrawUri(withdrawUri);
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
h2(() => {
walletInegrationApi.publishTalerAction(withdrawUri);
}, []);
const [notification, handleError] = useLocalNotificationHandler();
- const { api } = useBankCoreApiContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
const onAbortHandler = handleError(
async () => {
if (!creds)
return void 0;
- return api.abortWithdrawalById(
- creds,
- withdrawUri.withdrawalOperationId
- );
+ return api.abortWithdrawalById(creds, withdrawUri.withdrawalOperationId);
},
onAborted,
(fail) => {
@@ -34144,66 +33267,19 @@ function OperationNotFound({
)));
}
-// src/context/navigation.ts
-init_preact_module();
-init_hooks_module();
-var Context6 = B(void 0);
-var useNavigationContext = () => q2(Context6);
-function getPathAndParamsFromWindow() {
- const path = typeof window !== "undefined" ? window.location.hash.substring(1) : "/";
- const params = {};
- if (typeof window !== "undefined") {
- for (const [key, value] of new URLSearchParams(window.location.search)) {
- params[key] = value;
- }
- }
- return { path, params };
-}
-var { path: initialPath, params: initialParams } = getPathAndParamsFromWindow();
-var PopStateEventType = "popstate";
-var BrowserHashNavigationProvider = ({
- children
-}) => {
- const [{ path, params }, setState] = p3({
- path: initialPath,
- params: initialParams
- });
- if (typeof window === "undefined") {
- throw Error(
- "Can't use BrowserHashNavigationProvider if there is no window object"
- );
- }
- function navigateTo(path2) {
- const { params: params2 } = getPathAndParamsFromWindow();
- setState({ path: path2, params: params2 });
- window.location.href = path2;
- }
- h2(() => {
- function eventListener() {
- setState(getPathAndParamsFromWindow());
- }
- window.addEventListener(PopStateEventType, eventListener);
- return () => {
- window.removeEventListener(PopStateEventType, eventListener);
- };
- }, []);
- return h(Context6.Provider, {
- value: { path, params, navigateTo },
- children
- });
-};
-
// src/pages/SolveChallengePage.tsx
+var TAN_PREFIX = "T-";
+var TAN_REGEX = /^([Tt](-)?)?[0-9]*$/;
function SolveChallengePage({
onChallengeCompleted,
routeClose
}) {
- const { api } = useBankCoreApiContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
const { i18n: i18n2 } = useTranslationContext();
const [bankState, updateBankState] = useBankState();
const [code, setCode] = p3(void 0);
const [notification, notify2, handleError] = useLocalNotification();
- const { state } = useBackendState();
+ const { state } = useSessionState();
const creds = state.status !== "loggedIn" ? void 0 : state;
const { navigateTo } = useNavigationContext();
if (!bankState.currentChallenge) {
@@ -34219,7 +33295,7 @@ function SolveChallengePage({
}
const ch = bankState.currentChallenge;
const errors2 = undefinedIfEmpty({
- code: !code ? i18n2.str`Required` : void 0
+ code: !code ? i18n2.str`Required` : !TAN_REGEX.test(code) ? i18n2.str`Confirmation codes are numerical, possibly beginning with 'T-.'` : void 0
});
async function startChallenge() {
if (!creds)
@@ -34242,21 +33318,24 @@ function SolveChallengePage({
type: "error",
title: i18n2.str`Cashout not found. It may be also mean that it was already aborted.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Unauthorized:
return notify2({
type: "error",
title: i18n2.str`Cashout not found. It may be also mean that it was already aborted.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
return notify2({
type: "error",
title: i18n2.str`Cashout not found. It may be also mean that it was already aborted.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
default:
assertUnreachable(resp);
@@ -34267,11 +33346,10 @@ function SolveChallengePage({
async function completeChallenge() {
if (!creds || !code)
return;
+ const tan = code.toUpperCase().startsWith(TAN_PREFIX) ? code.substring(TAN_PREFIX.length) : code;
await handleError(async () => {
{
- const resp = await api.confirmChallenge(creds, ch.id, {
- tan: code
- });
+ const resp = await api.confirmChallenge(creds, ch.id, { tan });
if (resp.type === "fail") {
setCode("");
switch (resp.case) {
@@ -34280,35 +33358,40 @@ function SolveChallengePage({
type: "error",
title: i18n2.str`Challenge not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Unauthorized:
return notify2({
type: "error",
title: i18n2.str`This user is not authorized to complete this challenge.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.TooManyRequests:
return notify2({
type: "error",
title: i18n2.str`Too many attempts, try another code.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED:
return notify2({
type: "error",
title: i18n2.str`The confirmation code is wrong, try again.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_TAN_CHALLENGE_EXPIRED:
return notify2({
type: "error",
title: i18n2.str`The operation expired.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
default:
assertUnreachable(resp);
@@ -34340,7 +33423,8 @@ function SolveChallengePage({
type: "error",
title: i18n2.str`The operation failed.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
}
updateBankState("currentChallenge", {
@@ -34352,7 +33436,8 @@ function SolveChallengePage({
});
return notify2({
type: "info",
- title: i18n2.str`The operation needs another confirmation to complete.`
+ title: i18n2.str`The operation needs another confirmation to complete.`,
+ when: AbsoluteTime.now()
});
}
updateBankState("currentChallenge", void 0);
@@ -34360,30 +33445,14 @@ function SolveChallengePage({
}
});
}
- const subtitle = ((op) => {
- switch (op) {
- case "delete-account":
- return i18n2.str`Account delete`;
- case "update-account":
- return i18n2.str`Account update`;
- case "update-password":
- return i18n2.str`Password update`;
- case "create-transaction":
- return i18n2.str`Wire transfer`;
- case "confirm-withdrawal":
- return i18n2.str`Withdrawal`;
- case "create-cashout":
- return i18n2.str`Cashout`;
- }
- })(ch.operation);
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(
"span",
{
class: "text-sm text-black font-semibold leading-6 ",
id: "availability-label"
},
/* @__PURE__ */ h(i18n2.Translate, null, "Confirm the operation")
- )), /* @__PURE__ */ h("span", null, subtitle)), /* @__PURE__ */ h("div", { class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" }, /* @__PURE__ */ h(
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "This operation is protected with second factor authentication. In order to complete it we need to verify your identity using the authentication channel you provided."))), /* @__PURE__ */ h("div", { class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" }, /* @__PURE__ */ h(
ChallengeDetails,
{
challenge: bankState.currentChallenge,
@@ -34412,6 +33481,18 @@ function SolveChallengePage({
class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
value: code ?? "",
required: true,
+ onPaste: (e4) => {
+ e4.preventDefault();
+ const pasted = e4.clipboardData?.getData("text/plain");
+ if (!pasted)
+ return;
+ if (pasted.toUpperCase().startsWith(TAN_PREFIX)) {
+ const sub2 = pasted.substring(TAN_PREFIX.length);
+ setCode(sub2);
+ return;
+ }
+ setCode(pasted);
+ },
name: "answer",
id: "answer",
autocomplete: "off",
@@ -34425,7 +33506,16 @@ function SolveChallengePage({
message: errors2?.code,
isDirty: code !== void 0
}
- ))),
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, ((ch2) => {
+ switch (ch2) {
+ case TalerCorebankApi.TanChannel.SMS:
+ return /* @__PURE__ */ h(i18n2.Translate, null, "You should have received a code in your phone.");
+ case TalerCorebankApi.TanChannel.EMAIL:
+ return /* @__PURE__ */ h(i18n2.Translate, null, "You should have received a code in your email.");
+ default:
+ assertUnreachable(ch2);
+ }
+ })(ch.info.tan_channel)), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, 'The confirmation code starts with "', TAN_PREFIX, '" followed by numbers.'))),
/* @__PURE__ */ h("div", { class: "flex items-center justify-between border-gray-900/10 px-4 py-4 " }, /* @__PURE__ */ h("div", null), /* @__PURE__ */ h(
"button",
{
@@ -34447,7 +33537,7 @@ function ChallengeDetails({
onStart,
onCancel
}) {
- const { i18n: i18n2, dateLocale } = useTranslationContext();
+ const { i18n: i18n2 } = useTranslationContext();
const { config } = useBankCoreApiContext();
const firstTime = AbsoluteTime.isNever(challenge.sent);
h2(() => {
@@ -34455,17 +33545,26 @@ function ChallengeDetails({
onStart();
}
}, []);
- return /* @__PURE__ */ h("div", { class: "px-4 mt-4 " }, /* @__PURE__ */ h("div", { class: "w-full" }, /* @__PURE__ */ h("div", { class: "border-gray-100" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(
- "span",
- {
- class: "text-sm text-black font-semibold leading-6 ",
- id: "availability-label"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Operation details")
- )), /* @__PURE__ */ h("dl", { class: "divide-y divide-gray-100" }, (() => {
+ const subtitle = ((op) => {
+ switch (op) {
+ case "delete-account":
+ return i18n2.str`Removing account`;
+ case "update-account":
+ return i18n2.str`Updating account values`;
+ case "update-password":
+ return i18n2.str`Updating password`;
+ case "create-transaction":
+ return i18n2.str`Making a wire transfer`;
+ case "confirm-withdrawal":
+ return i18n2.str`Confirming withdrawal`;
+ case "create-cashout":
+ return i18n2.str`Making a cashout`;
+ }
+ })(challenge.operation);
+ return /* @__PURE__ */ h("div", { class: "px-4 mt-4 " }, /* @__PURE__ */ h("div", { class: "w-full" }, /* @__PURE__ */ h("div", { class: "border-gray-100" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-10 text-gray-900" }, /* @__PURE__ */ h("span", { class: " text-black font-semibold leading-6 " }, /* @__PURE__ */ h(i18n2.Translate, null, "Operation:")), " ", "\xA0", /* @__PURE__ */ h("span", { class: " text-black font-normal leading-6 " }, subtitle)), /* @__PURE__ */ h("dl", { class: "divide-y divide-gray-100" }, (() => {
switch (challenge.operation) {
case "delete-account":
- return /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Account")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, challenge.request));
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Type")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, /* @__PURE__ */ h(i18n2.Translate, null, "Updating account settings"))), /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Account")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, challenge.request)));
case "create-transaction": {
const payto = parsePaytoUri(challenge.request.payto_uri);
return /* @__PURE__ */ h(p2, null, challenge.request.amount && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Amount")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, /* @__PURE__ */ h(
@@ -34500,14 +33599,14 @@ function ChallengeDetails({
default:
assertUnreachable(challenge);
}
- })(), challenge.info && /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(
+ })()), challenge.info && /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900 mt-4" }, /* @__PURE__ */ h(
"span",
{
class: "text-sm text-black font-semibold leading-6 ",
id: "availability-label"
},
/* @__PURE__ */ h(i18n2.Translate, null, "Challenge details")
- )), challenge.sent.t_ms !== "never" && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Sent at")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, /* @__PURE__ */ h(
+ )), /* @__PURE__ */ h("dl", { class: "divide-y divide-gray-100" }, challenge.sent.t_ms !== "never" && /* @__PURE__ */ h("div", { class: "px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" }, /* @__PURE__ */ h("dt", { class: "text-sm font-medium leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Sent at")), /* @__PURE__ */ h("dd", { class: "mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0" }, /* @__PURE__ */ h(
Time,
{
format: "dd/MM/yyyy HH:mm:ss",
@@ -34595,14 +33694,7 @@ function ShowCashoutDetails({
if (info.type === "fail") {
switch (info.case) {
case HttpStatusCode.NotImplemented: {
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "danger",
- title: i18n2.str`Cashout are disabled`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.")
- );
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
}
default:
assertUnreachable(info.case);
@@ -34623,6 +33715,65 @@ function ShowCashoutDetails({
))));
}
+// src/pages/WireTransfer.tsx
+init_preact_module();
+function WireTransfer({
+ toAccount,
+ withSubject,
+ withAmount,
+ onAuthorizationRequired,
+ routeCancel,
+ routeHere,
+ onSuccess
+}) {
+ const { i18n: i18n2 } = useTranslationContext();
+ const r3 = useSessionState();
+ const account = r3.state.status !== "loggedOut" ? r3.state.username : "admin";
+ const result = useAccountDetails(account);
+ if (!result) {
+ return /* @__PURE__ */ h(Loading, null);
+ }
+ if (result instanceof TalerError) {
+ return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: result });
+ }
+ if (result.type === "fail") {
+ switch (result.case) {
+ case HttpStatusCode.Unauthorized:
+ return /* @__PURE__ */ h(LoginForm, { currentUser: account });
+ case HttpStatusCode.NotFound:
+ return /* @__PURE__ */ h(LoginForm, { currentUser: account });
+ default:
+ assertUnreachable(result);
+ }
+ }
+ const { body: data } = result;
+ const balance = Amounts.parseOrThrow(data.balance.amount);
+ const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
+ const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
+ if (!balance)
+ return /* @__PURE__ */ h(p2, null);
+ const limit = balanceIsDebit ? Amounts.sub(debitThreshold, balance).amount : Amounts.add(balance, debitThreshold).amount;
+ const positiveBalance = balanceIsDebit ? Amounts.zeroOfAmount(balance) : balance;
+ return /* @__PURE__ */ h("div", { class: "px-4 mt-8" }, /* @__PURE__ */ h("div", { class: "sm:flex sm:items-center mb-4" }, /* @__PURE__ */ h("div", { class: "sm:flex-auto" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Make a wire transfer")))), /* @__PURE__ */ h(
+ PaytoWireTransferForm,
+ {
+ withAccount: toAccount,
+ withAmount,
+ balance: positiveBalance,
+ withSubject,
+ routeHere,
+ limit,
+ onAuthorizationRequired,
+ onSuccess: () => {
+ notifyInfo(i18n2.str`Wire transfer created!`);
+ if (onSuccess)
+ onSuccess();
+ },
+ routeCancel
+ }
+ ));
+}
+
// src/pages/WithdrawalOperationPage.tsx
init_preact_module();
function WithdrawalOperationPage({
@@ -34632,9 +33783,9 @@ function WithdrawalOperationPage({
routeClose,
routeWithdrawalDetails
}) {
- const { api } = useBankCoreApiContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
const uri = stringifyWithdrawUri({
- bankIntegrationApiBaseUrl: api.getIntegrationAPI().baseUrl,
+ bankIntegrationApiBaseUrl: api.getIntegrationAPI().href,
withdrawalOperationId: operationId
});
const parsedUri = parseWithdrawUri(uri);
@@ -34706,14 +33857,7 @@ function FailedView2({ error: error2 }) {
const { i18n: i18n2 } = useTranslationContext();
switch (error2.case) {
case HttpStatusCode.NotImplemented: {
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "danger",
- title: i18n2.str`Cashout are disabled`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.")
- );
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
}
default:
assertUnreachable(error2.case);
@@ -34734,14 +33878,7 @@ function ReadyView4({
if (resp.type === "fail") {
switch (resp.case) {
case HttpStatusCode.NotImplemented: {
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "danger",
- title: i18n2.str`Cashout are disabled`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.")
- );
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
}
default:
assertUnreachable(resp.case);
@@ -34814,7 +33951,9 @@ function ReadyView4({
Time,
{
format: "HH:mm:ss",
- timestamp: AbsoluteTime.fromProtocolTimestamp(item.creation_time)
+ timestamp: AbsoluteTime.fromProtocolTimestamp(
+ item.creation_time
+ )
}
))),
/* @__PURE__ */ h("td", { class: "hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer" }, /* @__PURE__ */ h(
@@ -34861,7 +34000,7 @@ function ProfileNavigation({
}) {
const { i18n: i18n2 } = useTranslationContext();
const { config } = useBankCoreApiContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const isAdminUser = credentials.status !== "loggedIn" ? false : credentials.isUserAdministrator;
const nonAdminUser = !isAdminUser;
const { navigateTo } = useNavigationContext();
@@ -35004,7 +34143,7 @@ function ProfileNavigation({
)));
}
-// src/pages/business/CreateCashout.tsx
+// src/pages/regional/CreateCashout.tsx
init_preact_module();
init_hooks_module();
function CreateCashout({
@@ -35020,10 +34159,10 @@ function CreateCashout({
estimateByCredit: calculateFromCredit,
estimateByDebit: calculateFromDebit
} = useCashoutEstimator();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
const [, updateBankState] = useBankState();
- const { api, config, hints } = useBankCoreApiContext();
+ const { lib: { bank: api }, config, hints } = useBankCoreApiContext();
const [form, setForm] = p3({ isDebit: true });
const [notification, notify2, handleError] = useLocalNotification();
const info = useConversionInfo();
@@ -35038,7 +34177,6 @@ function CreateCashout({
/* @__PURE__ */ h(i18n2.Translate, null, "Close")
)));
}
- const OLD_CASHOUT_API = hints.indexOf(0 /* CASHOUT_BEFORE_2FA */) !== -1;
if (!resultAccount) {
return /* @__PURE__ */ h(Loading, null);
}
@@ -35064,14 +34202,7 @@ function CreateCashout({
if (info.type === "fail") {
switch (info.case) {
case HttpStatusCode.NotImplemented: {
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "danger",
- title: i18n2.str`Cashout are disabled`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.")
- );
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
}
default:
assertUnreachable(info.case);
@@ -35128,14 +34259,16 @@ function CreateCashout({
}
const errors2 = undefinedIfEmpty({
subject: !form.subject ? i18n2.str`Required` : void 0,
- amount: !form.amount ? i18n2.str`Required` : !inputAmount ? i18n2.str`Invalid` : Amounts.cmp(limit, calc.debit) === -1 ? i18n2.str`Balance is not enough` : form.isDebit && Amounts.cmp(inputAmount, conversionInfo.cashout_min_amount) < 1 ? i18n2.str`Needs to be higher than ${Amounts.stringifyValueWithSpec(Amounts.parseOrThrow(conversionInfo.cashout_min_amount), regional_currency_specification).normal}` : calculationResult === "amount-is-too-small" ? i18n2.str`Amount needs to be higher` : Amounts.isZero(calc.credit) ? i18n2.str`The total transfer at destination will be zero` : void 0,
- channel: OLD_CASHOUT_API && !form.channel ? i18n2.str`Required` : void 0
+ amount: !form.amount ? i18n2.str`Required` : !inputAmount ? i18n2.str`Invalid` : Amounts.cmp(limit, calc.debit) === -1 ? i18n2.str`Balance is not enough` : form.isDebit && Amounts.cmp(inputAmount, conversionInfo.cashout_min_amount) < 1 ? i18n2.str`Needs to be higher than ${Amounts.stringifyValueWithSpec(
+ Amounts.parseOrThrow(conversionInfo.cashout_min_amount),
+ regional_currency_specification
+ ).normal}` : calculationResult === "amount-is-too-small" ? i18n2.str`Amount needs to be higher` : Amounts.isZero(calc.credit) ? i18n2.str`The total transfer at destination will be zero` : void 0
});
const trimmedAmountStr = form.amount?.trim();
async function createCashout() {
const request_uid = encodeCrock(getRandomBytes(32));
await handleError(async () => {
- const validChannel = !OLD_CASHOUT_API || config.supported_tan_channels.length === 0 || form.channel;
+ const validChannel = config.supported_tan_channels.length === 0 || form.channel;
if (!creds || !form.subject || !validChannel)
return;
const request = {
@@ -35165,49 +34298,56 @@ function CreateCashout({
type: "error",
title: i18n2.str`Account not found`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED:
return notify2({
type: "error",
title: i18n2.str`Duplicated request detected, check if the operation succeeded or try again.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_BAD_CONVERSION:
return notify2({
type: "error",
title: i18n2.str`The conversion rate was incorrectly applied`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return notify2({
type: "error",
title: i18n2.str`The account does not have sufficient funds`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotImplemented:
return notify2({
type: "error",
title: i18n2.str`Cashout are disabled`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
return notify2({
type: "error",
title: i18n2.str`Missing cashout URI in the profile`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
return notify2({
type: "error",
title: i18n2.str`Sending the confirmation message failed, retry later or contact the administrator.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
}
assertUnreachable(resp);
@@ -35218,7 +34358,7 @@ function CreateCashout({
const cashoutAccount = !resultAccount.body.cashout_payto_uri ? void 0 : parsePaytoUri(resultAccount.body.cashout_payto_uri);
const cashoutAccountName = !cashoutAccount ? void 0 : cashoutAccount.targetPath;
const cashoutLegalName = !cashoutAccount ? void 0 : cashoutAccount.params["receiver-name"];
- return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("section", { class: "mt-4 rounded-sm px-4 py-6 p-8 " }, /* @__PURE__ */ h("h2", { id: "summary-heading", class: "font-medium text-lg" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout")), /* @__PURE__ */ h("dl", { class: "mt-4 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex" }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Conversion rate")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, sellRate)), /* @__PURE__ */ h("div", { class: "flex items-center justify-between border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "flex items-center text-sm text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Balance"))), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("section", { class: "mt-4 rounded-sm px-4 py-6 p-8 " }, /* @__PURE__ */ h("h2", { id: "summary-heading", class: "font-medium text-lg" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout")), /* @__PURE__ */ h("dl", { class: "mt-4 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex" }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Conversion rate")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, sellRate)), /* @__PURE__ */ h("div", { class: "flex items-center justify-between border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "flex items-center text-sm text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Balance"))), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
RenderAmount,
{
value: account.balance,
@@ -35306,7 +34446,17 @@ function CreateCashout({
"clip-rule": "evenodd"
}
)
- ) : /* @__PURE__ */ h("svg", { fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor", class: "w-5 h-5" }, /* @__PURE__ */ h("path", { d: "M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" })),
+ ) : /* @__PURE__ */ h(
+ "svg",
+ {
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "1.5",
+ stroke: "currentColor",
+ class: "w-5 h-5"
+ },
+ /* @__PURE__ */ h("path", { d: "M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" })
+ ),
/* @__PURE__ */ h(i18n2.Translate, null, "Send ", regional_currency)
), /* @__PURE__ */ h(
"button",
@@ -35336,7 +34486,17 @@ function CreateCashout({
"clip-rule": "evenodd"
}
)
- ) : /* @__PURE__ */ h("svg", { fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor", class: "w-5 h-5" }, /* @__PURE__ */ h("path", { d: "M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" })),
+ ) : /* @__PURE__ */ h(
+ "svg",
+ {
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "1.5",
+ stroke: "currentColor",
+ class: "w-5 h-5"
+ },
+ /* @__PURE__ */ h("path", { d: "M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" })
+ ),
/* @__PURE__ */ h(i18n2.Translate, null, "Receive ", fiat_currency)
))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex justify-between" }, /* @__PURE__ */ h(
"label",
@@ -35391,119 +34551,7 @@ function CreateCashout({
withColor: true,
spec: fiat_currency_specification
}
- ))))), !OLD_CASHOUT_API ? void 0 : config.supported_tan_channels.length === 0 ? /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
- Attention,
- {
- type: "warning",
- title: i18n2.str`No cashout channel available`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Before doing a cashout the server need to provide an second channel to confirm the operation")
- )) : /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
- "label",
- {
- class: "block text-sm font-medium leading-6 text-gray-900",
- for: "channel"
- },
- i18n2.str`Second factor authentication`
- ), /* @__PURE__ */ h("div", { class: "mt-2 max-w-xl text-sm text-gray-500" }, /* @__PURE__ */ h("div", { class: "px-4 mt-4 grid grid-cols-1 gap-y-6" }, config.supported_tan_channels.indexOf(
- "email" /* EMAIL */
- ) === -1 ? void 0 : /* @__PURE__ */ h(
- "label",
- {
- onClick: () => {
- if (!resultAccount.body.contact_data?.email)
- return;
- form.channel = "email" /* EMAIL */;
- updateForm(structuredClone(form));
- },
- "data-disabled": !resultAccount.body.contact_data?.email,
- "data-selected": form.channel === "email" /* EMAIL */,
- class: "relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- },
- /* @__PURE__ */ h(
- "input",
- {
- type: "radio",
- name: "channel",
- value: "Newsletter",
- class: "sr-only"
- }
- ),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-0-label",
- class: "block text-sm font-medium text-gray-900 "
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Email")
- ), !resultAccount.body.contact_data?.email && i18n2.str`Add a email in your profile to enable this option`)),
- /* @__PURE__ */ h(
- "svg",
- {
- "data-selected": form.channel === "email" /* EMAIL */,
- class: "h-5 w-5 text-indigo-600 data-[selected=false]:hidden",
- viewBox: "0 0 20 20",
- fill: "currentColor",
- "aria-hidden": "true"
- },
- /* @__PURE__ */ h(
- "path",
- {
- "fill-rule": "evenodd",
- d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
- "clip-rule": "evenodd"
- }
- )
- )
- ), config.supported_tan_channels.indexOf("sms" /* SMS */) === -1 ? void 0 : /* @__PURE__ */ h(
- "label",
- {
- onClick: () => {
- if (!resultAccount.body.contact_data?.phone)
- return;
- form.channel = "sms" /* SMS */;
- updateForm(structuredClone(form));
- },
- "data-disabled": !resultAccount.body.contact_data?.phone,
- "data-selected": form.channel === "sms" /* SMS */,
- class: "relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- },
- /* @__PURE__ */ h(
- "input",
- {
- type: "radio",
- name: "channel",
- value: "Existing Customers",
- class: "sr-only"
- }
- ),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-1-label",
- class: "block text-sm font-medium text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "SMS")
- ), !resultAccount.body.contact_data?.phone && i18n2.str`Add a phone number in your profile to enable this option`)),
- /* @__PURE__ */ h(
- "svg",
- {
- "data-selected": form.channel === "sms" /* SMS */,
- class: "h-5 w-5 text-indigo-600 data-[selected=false]:hidden",
- viewBox: "0 0 20 20",
- fill: "currentColor",
- "aria-hidden": "true"
- },
- /* @__PURE__ */ h(
- "path",
- {
- "fill-rule": "evenodd",
- d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
- "clip-rule": "evenodd"
- }
- )
- )
- )))))),
+ ))))))),
/* @__PURE__ */ h("div", { class: "flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8" }, /* @__PURE__ */ h(
"a",
{
@@ -35544,7 +34592,7 @@ function CashoutListForAccount({
routeClose
}) {
const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const accountIsTheCurrentUser = credentials.status === "loggedIn" ? credentials.username === account : false;
return /* @__PURE__ */ h(p2, null, accountIsTheCurrentUser ? /* @__PURE__ */ h(
ProfileNavigation,
@@ -35585,9 +34633,9 @@ function AccountForm({
focus,
children
}) {
- const { config, hints, url } = useBankCoreApiContext();
+ const { config, url } = useBankCoreApiContext();
const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const [form, setForm] = p3({});
const [errors2, setErrors] = p3(void 0);
const paytoType = config.wire_type === "X_TALER_BANK" ? "x-taler-bank" : "iban";
@@ -35606,7 +34654,6 @@ function AccountForm({
username: username ?? "",
tan_channel: template?.tan_channel
};
- const OLD_CASHOUT_API = hints.indexOf(0 /* CASHOUT_BEFORE_2FA */) !== -1;
const userIsAdmin = credentials.status !== "loggedIn" ? false : credentials.isUserAdministrator;
const editableUsername = purpose === "create";
const editableName = purpose === "create" || purpose === "update" && (config.allow_edit_name || userIsAdmin);
@@ -35614,8 +34661,6 @@ function AccountForm({
const editableCashout = purpose === "create" || purpose === "update" && (config.allow_edit_cashout_payto_uri || userIsAdmin);
const editableThreshold = userIsAdmin && (purpose === "create" || purpose === "update");
const editableAccount = purpose === "create" && userIsAdmin;
- const hasPhone = !!defaultValue.phone || !!form.phone;
- const hasEmail = !!defaultValue.email || !!form.email;
function updateForm(newForm) {
const trimmedAmountStr = newForm.debit_threshold?.trim();
const parsedAmount = Amounts.parse(
@@ -35641,7 +34686,11 @@ function AccountForm({
if (newForm.cashout_payto_uri)
switch (cashoutPaytoType) {
case "x-taler-bank": {
- cashout = buildPayto("x-taler-bank", url.host, newForm.cashout_payto_uri);
+ cashout = buildPayto(
+ "x-taler-bank",
+ url.host,
+ newForm.cashout_payto_uri
+ );
break;
}
case "iban": {
@@ -35878,120 +34927,7 @@ function AccountForm({
value: form.cashout_payto_uri ?? defaultValue.cashout_payto_uri,
disabled: !editableCashout
}
- ), OLD_CASHOUT_API || config.supported_tan_channels.length === 0 ? void 0 : /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
- "label",
- {
- class: "block text-sm font-medium leading-6 text-gray-900",
- for: "channel"
- },
- i18n2.str`Enable second factor authentication`
- ), /* @__PURE__ */ h("div", { class: "mt-2 max-w-xl text-sm text-gray-500" }, /* @__PURE__ */ h("div", { class: "px-4 mt-4 grid grid-cols-1 gap-y-6" }, config.supported_tan_channels.indexOf("email" /* EMAIL */) === -1 ? void 0 : /* @__PURE__ */ h(
- "label",
- {
- onClick: (e4) => {
- if (!hasEmail)
- return;
- if (form.tan_channel === "email" /* EMAIL */) {
- form.tan_channel = "remove";
- } else {
- form.tan_channel = "email" /* EMAIL */;
- }
- updateForm(structuredClone(form));
- e4.preventDefault();
- },
- "data-disabled": purpose === "show" || !hasEmail,
- "data-selected": (form.tan_channel ?? defaultValue.tan_channel) === "email" /* EMAIL */,
- class: "relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- },
- /* @__PURE__ */ h(
- "input",
- {
- type: "radio",
- name: "channel",
- value: "Newsletter",
- class: "sr-only"
- }
- ),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-0-label",
- class: "block text-sm font-medium text-gray-900 "
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Using email")
- ), purpose !== "show" && !hasEmail && i18n2.str`Add an email in your profile to enable this option`)),
- /* @__PURE__ */ h(
- "svg",
- {
- "data-selected": (form.tan_channel ?? defaultValue.tan_channel) === "email" /* EMAIL */,
- class: "h-5 w-5 text-indigo-600 data-[selected=false]:hidden",
- viewBox: "0 0 20 20",
- fill: "currentColor",
- "aria-hidden": "true"
- },
- /* @__PURE__ */ h(
- "path",
- {
- "fill-rule": "evenodd",
- d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
- "clip-rule": "evenodd"
- }
- )
- )
- ), config.supported_tan_channels.indexOf("sms" /* SMS */) === -1 ? void 0 : /* @__PURE__ */ h(
- "label",
- {
- onClick: (e4) => {
- if (!hasPhone)
- return;
- if (form.tan_channel === "sms" /* SMS */) {
- form.tan_channel = "remove";
- } else {
- form.tan_channel = "sms" /* SMS */;
- }
- updateForm(structuredClone(form));
- e4.preventDefault();
- },
- "data-disabled": purpose === "show" || !hasPhone,
- "data-selected": (form.tan_channel ?? defaultValue.tan_channel) === "sms" /* SMS */,
- class: "relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- },
- /* @__PURE__ */ h(
- "input",
- {
- type: "radio",
- name: "channel",
- value: "Existing Customers",
- class: "sr-only"
- }
- ),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-1-label",
- class: "block text-sm font-medium text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Using SMS")
- ), purpose !== "show" && !hasPhone && i18n2.str`Add a phone number in your profile to enable this option`)),
- /* @__PURE__ */ h(
- "svg",
- {
- "data-selected": (form.tan_channel ?? defaultValue.tan_channel) === "sms" /* SMS */,
- class: "h-5 w-5 text-indigo-600 data-[selected=false]:hidden",
- viewBox: "0 0 20 20",
- fill: "currentColor",
- "aria-hidden": "true"
- },
- /* @__PURE__ */ h(
- "path",
- {
- "fill-rule": "evenodd",
- d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
- "clip-rule": "evenodd"
- }
- )
- )
- )))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ ), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
"label",
{
for: "debit",
@@ -36113,9 +35049,9 @@ function ShowAccountDetails({
routeConversionConfig
}) {
const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" ? void 0 : credentials;
- const { api } = useBankCoreApiContext();
+ const { lib: { bank } } = useBankCoreApiContext();
const accountIsTheCurrentUser = credentials.status === "loggedIn" ? credentials.username === account : false;
const [submitAccount, setSubmitAccount] = p3();
const [notification, notify2, handleError] = useLocalNotification();
@@ -36140,7 +35076,7 @@ function ShowAccountDetails({
if (!submitAccount || !creds)
return;
await handleError(async () => {
- const resp = await api.updateAccount(
+ const resp = await bank.updateAccount(
{
token: creds.token,
username: account
@@ -36157,42 +35093,48 @@ function ShowAccountDetails({
type: "error",
title: i18n2.str`The rights to change the account are not sufficient`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The username was not found`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME:
return notify2({
type: "error",
title: i18n2.str`You can't change the legal name, please contact the your account administrator.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
return notify2({
type: "error",
title: i18n2.str`You can't change the debt limit, please contact the your account administrator.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT:
return notify2({
type: "error",
title: i18n2.str`You can't change the cashout address, please contact the your account administrator.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_MISSING_TAN_INFO:
return notify2({
type: "error",
title: i18n2.str`No information for the selected authentication channel.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Accepted: {
updateBankState("currentChallenge", {
@@ -36209,7 +35151,8 @@ function ShowAccountDetails({
type: "error",
title: i18n2.str`Authentication channel is not supported.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
}
default:
@@ -36218,6 +35161,41 @@ function ShowAccountDetails({
}
});
}
+ const url = bank.getRevenueAPI(account);
+ url.username = account;
+ const baseURL = url.href;
+ const ac = parsePaytoUri(result.body.payto_uri);
+ const payto = !ac?.isKnown ? void 0 : ac;
+ let accountLetter = void 0;
+ if (payto) {
+ switch (payto.targetType) {
+ case "iban": {
+ accountLetter = `account-info-url=${url.href}
+account-type=${payto.targetType}
+iban=${payto.iban}
+receiver-name=${result.body.name}
+`;
+ break;
+ }
+ case "x-taler-bank": {
+ accountLetter = `account-info-url=${url.href}
+account-type=${payto.targetType}
+account=${payto.account}
+host=${payto.host}
+receiver-name=${result.body.name}
+`;
+ break;
+ }
+ case "bitcoin": {
+ accountLetter = `account-info-url=${url.href}
+account-type=${payto.targetType}
+address=${payto.address}
+receiver-name=${result.body.name}
+`;
+ break;
+ }
+ }
+ }
return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(LocalNotificationBanner, { notification, showDebug: true }), accountIsTheCurrentUser ? /* @__PURE__ */ h(
ProfileNavigation,
{
@@ -36228,7 +35206,7 @@ function ShowAccountDetails({
routeMyAccountDetails,
routeMyAccountPassword
}
- ) : /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Account "', account, '"')), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ ) : /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Account "', account, '"')), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
"span",
{
class: "text-sm text-black font-semibold leading-6 ",
@@ -36263,7 +35241,149 @@ function ShowAccountDetails({
},
/* @__PURE__ */ h(i18n2.Translate, null, "Update")
))
- )));
+ )), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-semibold leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Merchant integration")
+ )))), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Use this information to link your Taler Merchant Backoffice account with the current bank account. You can start by copying the values, then go to your merchant backoffice service provider, login into your account and look for the "import" button in the "bank account" section.'))), payto !== void 0 && /* @__PURE__ */ h("div", { class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" }, /* @__PURE__ */ h("div", { class: "px-4 py-6 sm:p-8" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ "label",
+ {
+ class: "block text-sm font-medium leading-6 text-gray-900",
+ for: "account-type"
+ },
+ i18n2.str`Account type`
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "text",
+ class: "block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ name: "account-type",
+ id: "account-type",
+ disabled: true,
+ value: account,
+ autocomplete: "off"
+ }
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Method to use for wire transfer."))), ((payto2) => {
+ switch (payto2.targetType) {
+ case "iban": {
+ return /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ "label",
+ {
+ class: "block text-sm font-medium leading-6 text-gray-900",
+ for: "iban"
+ },
+ i18n2.str`IBAN`
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "text",
+ class: "block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ name: "iban",
+ id: "iban",
+ disabled: true,
+ value: payto2.iban,
+ autocomplete: "off"
+ }
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "International Bank Account Number.")));
+ }
+ case "x-taler-bank": {
+ return /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ "label",
+ {
+ class: "block text-sm font-medium leading-6 text-gray-900",
+ for: "iban"
+ },
+ i18n2.str`IBAN`
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "text",
+ class: "block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ name: "iban",
+ id: "iban",
+ disabled: true,
+ value: payto2.account,
+ autocomplete: "off"
+ }
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "International Bank Account Number.")));
+ }
+ case "bitcoin": {
+ return /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ "label",
+ {
+ class: "block text-sm font-medium leading-6 text-gray-900",
+ for: "iban"
+ },
+ i18n2.str`Address`
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "text",
+ class: "block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ name: "iban",
+ id: "iban",
+ disabled: true,
+ value: "DE1231231231",
+ autocomplete: "off"
+ }
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "International Bank Account Number.")));
+ }
+ }
+ })(payto), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ "label",
+ {
+ class: "block text-sm font-medium leading-6 text-gray-900",
+ for: "iban"
+ },
+ i18n2.str`Owner's name`
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "text",
+ class: "block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ name: "iban",
+ id: "iban",
+ disabled: true,
+ value: result.body.name,
+ autocomplete: "off"
+ }
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Legal name of the person holding the account."))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ "label",
+ {
+ class: "block text-sm font-medium leading-6 text-gray-900",
+ for: "iban"
+ },
+ i18n2.str`Account info URL`
+ ), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
+ "input",
+ {
+ type: "text",
+ class: "block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
+ name: "iban",
+ id: "iban",
+ disabled: true,
+ value: baseURL,
+ autocomplete: "off"
+ }
+ )), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "From where the merchant can download information about incoming wire transfers to this account."))))), /* @__PURE__ */ h("div", { class: "flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8" }, /* @__PURE__ */ h(
+ "a",
+ {
+ href: routeClose.url({}),
+ name: "cancel",
+ class: "text-sm font-semibold leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")
+ ), /* @__PURE__ */ h(
+ CopyButton,
+ {
+ getContent: () => accountLetter ?? "",
+ class: "flex text-center disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Copy")
+ )))));
}
// src/pages/account/UpdateAccountPassword.tsx
@@ -36283,9 +35403,9 @@ function UpdateAccountPassword({
routeHere
}) {
const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- const { api } = useBankCoreApiContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
const [current, setCurrent] = p3();
const [password, setPassword] = p3();
const [repeat, setRepeat] = p3();
@@ -36317,22 +35437,34 @@ function UpdateAccountPassword({
case HttpStatusCode.Unauthorized:
return notify2({
type: "error",
- title: i18n2.str`Not authorized to change the password, maybe the session is invalid.`
+ title: i18n2.str`Not authorized to change the password, maybe the session is invalid.`,
+ description: resp.detail.hint,
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
- title: i18n2.str`Account not found`
+ title: i18n2.str`Account not found`,
+ description: resp.detail.hint,
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD:
return notify2({
type: "error",
- title: i18n2.str`You need to provide the old password. If you don't have it contact your account administrator.`
+ title: i18n2.str`You need to provide the old password. If you don't have it contact your account administrator.`,
+ description: resp.detail.hint,
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD:
return notify2({
type: "error",
- title: i18n2.str`Your current password doesn't match, can't change to a new password.`
+ title: i18n2.str`Your current password doesn't match, can't change to a new password.`,
+ description: resp.detail.hint,
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Accepted: {
updateBankState("currentChallenge", {
@@ -36360,7 +35492,7 @@ function UpdateAccountPassword({
routeMyAccountPassword,
routeConversionConfig
}
- ) : /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Account "', accountName, '"')), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Update password"))), /* @__PURE__ */ h(
+ ) : /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Account "', accountName, '"')), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Update password"))), /* @__PURE__ */ h(
"form",
{
class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2",
@@ -36376,7 +35508,8 @@ function UpdateAccountPassword({
class: "block text-sm font-medium leading-6 text-gray-900",
for: "password"
},
- i18n2.str`Current password`
+ i18n2.str`Current password`,
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
"input",
{
@@ -36403,7 +35536,8 @@ function UpdateAccountPassword({
class: "block text-sm font-medium leading-6 text-gray-900",
for: "password"
},
- i18n2.str`New password`
+ i18n2.str`New password`,
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
"input",
{
@@ -36431,7 +35565,8 @@ function UpdateAccountPassword({
class: "block text-sm font-medium leading-6 text-gray-900",
for: "repeat"
},
- i18n2.str`Type it again`
+ i18n2.str`Type it again`,
+ /* @__PURE__ */ h("b", { style: { color: "red" } }, " *")
), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
"input",
{
@@ -36478,6 +35613,516 @@ function UpdateAccountPassword({
)));
}
+// src/pages/admin/AdminHome.tsx
+init_preact_module();
+init_hooks_module();
+
+// src/pages/admin/AccountList.tsx
+init_preact_module();
+function AccountList({
+ routeCreate,
+ routeRemoveAccount,
+ routeShowAccount,
+ routeUpdatePasswordAccount
+}) {
+ const result = useBusinessAccounts();
+ const { i18n: i18n2 } = useTranslationContext();
+ const { config } = useBankCoreApiContext();
+ if (!result) {
+ return /* @__PURE__ */ h(Loading, null);
+ }
+ if (result instanceof TalerError) {
+ return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: result });
+ }
+ if (result.data.type === "fail") {
+ switch (result.data.case) {
+ case HttpStatusCode.Unauthorized:
+ return /* @__PURE__ */ h(p2, null);
+ default:
+ assertUnreachable(result.data.case);
+ }
+ }
+ const onGoStart = result.isFirstPage ? void 0 : result.loadFirst;
+ const onGoNext = result.isLastPage ? void 0 : result.loadNext;
+ const accounts = result.result;
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 sm:px-6 lg:px-8 mt-8" }, /* @__PURE__ */ h("div", { class: "sm:flex sm:items-center" }, /* @__PURE__ */ h("div", { class: "sm:flex-auto" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Accounts"))), /* @__PURE__ */ h("div", { class: "mt-4 sm:ml-16 sm:mt-0 sm:flex-none" }, /* @__PURE__ */ h(
+ "a",
+ {
+ href: routeCreate.url({}),
+ name: "create account",
+ type: "button",
+ class: "block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Create account")
+ ))), /* @__PURE__ */ h("div", { class: "mt-4 flow-root" }, /* @__PURE__ */ h("div", { class: "-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8" }, /* @__PURE__ */ h("div", { class: "inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8" }, !accounts.length ? /* @__PURE__ */ h("div", null) : /* @__PURE__ */ h("table", { class: "min-w-full divide-y divide-gray-300" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h(
+ "th",
+ {
+ scope: "col",
+ class: "py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0"
+ },
+ i18n2.str`Username`
+ ), /* @__PURE__ */ h(
+ "th",
+ {
+ scope: "col",
+ class: "px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
+ },
+ i18n2.str`Name`
+ ), /* @__PURE__ */ h(
+ "th",
+ {
+ scope: "col",
+ class: "px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
+ },
+ i18n2.str`Balance`
+ ), /* @__PURE__ */ h("th", { scope: "col", class: "relative py-3.5 pl-3 pr-4 sm:pr-0" }, /* @__PURE__ */ h("span", { class: "sr-only" }, i18n2.str`Actions`)))), /* @__PURE__ */ h("tbody", { class: "divide-y divide-gray-200" }, accounts.map((item, idx) => {
+ const balance = !item.balance ? void 0 : Amounts.parse(item.balance.amount);
+ const noBalance = Amounts.isZero(item.balance.amount);
+ const balanceIsDebit = item.balance && item.balance.credit_debit_indicator == "debit";
+ return /* @__PURE__ */ h("tr", { key: idx }, /* @__PURE__ */ h("td", { class: "whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-0" }, /* @__PURE__ */ h(
+ "a",
+ {
+ name: `show account ${item.username}`,
+ href: routeShowAccount.url({
+ account: item.username
+ }),
+ class: "text-indigo-600 hover:text-indigo-900"
+ },
+ item.username
+ )), /* @__PURE__ */ h("td", { class: "whitespace-nowrap px-3 py-4 text-sm text-gray-500" }, item.name), /* @__PURE__ */ h(
+ "td",
+ {
+ "data-negative": noBalance ? void 0 : balanceIsDebit ? "true" : "false",
+ class: "whitespace-nowrap px-3 py-4 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600 "
+ },
+ !balance ? i18n2.str`Unknown` : /* @__PURE__ */ h("span", { class: "amount" }, /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: balance,
+ negative: balanceIsDebit,
+ spec: config.currency_specification
+ }
+ ))
+ ), /* @__PURE__ */ h("td", { class: "relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0" }, /* @__PURE__ */ h(
+ "a",
+ {
+ name: `update password ${item.username}`,
+ href: routeUpdatePasswordAccount.url({
+ account: item.username
+ }),
+ class: "text-indigo-600 hover:text-indigo-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Change password")
+ ), /* @__PURE__ */ h("br", null), noBalance ? /* @__PURE__ */ h(
+ "a",
+ {
+ name: `remove account ${item.username}`,
+ href: routeRemoveAccount.url({
+ account: item.username
+ }),
+ class: "text-indigo-600 hover:text-indigo-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Remove")
+ ) : void 0));
+ })))), /* @__PURE__ */ h(
+ "nav",
+ {
+ class: "flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg",
+ "aria-label": "Pagination"
+ },
+ /* @__PURE__ */ h("div", { class: "flex flex-1 justify-between sm:justify-end" }, /* @__PURE__ */ h(
+ "button",
+ {
+ name: "first page",
+ class: "relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0",
+ disabled: !onGoStart,
+ onClick: onGoStart
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "First page")
+ ), /* @__PURE__ */ h(
+ "button",
+ {
+ name: "next page",
+ class: "relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0",
+ disabled: !onGoNext,
+ onClick: onGoNext
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Next")
+ ))
+ )))));
+}
+
+// src/pages/admin/AdminHome.tsx
+function AdminHome({
+ routeCreate,
+ routeRemoveAccount,
+ routeShowAccount,
+ routeUpdatePasswordAccount,
+ routeDownloadStats,
+ routeCreateWireTransfer,
+ onAuthorizationRequired
+}) {
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(Metrics, { routeDownloadStats }), /* @__PURE__ */ h(
+ WireTransfer,
+ {
+ routeHere: routeCreateWireTransfer,
+ onAuthorizationRequired
+ }
+ ), /* @__PURE__ */ h(
+ Transactions,
+ {
+ account: "admin",
+ routeCreateWireTransfer
+ }
+ ), /* @__PURE__ */ h(
+ AccountList,
+ {
+ routeCreate,
+ routeRemoveAccount,
+ routeShowAccount,
+ routeUpdatePasswordAccount
+ }
+ ));
+}
+function getDateForTimeframe(which, timeframe, locale6) {
+ const time = Date.now();
+ switch (timeframe) {
+ case TalerCorebankApi.MonitorTimeframeParam.hour:
+ return `${format(setHours(time, which), "HH", { locale: locale6 })}hs`;
+ case TalerCorebankApi.MonitorTimeframeParam.day:
+ return format(setDate(time, which), "EEEE", { locale: locale6 });
+ case TalerCorebankApi.MonitorTimeframeParam.month:
+ return format(setMonth(time, which), "MMMM", { locale: locale6 });
+ case TalerCorebankApi.MonitorTimeframeParam.year:
+ return format(setYear(time, which), "yyyy", { locale: locale6 });
+ case TalerCorebankApi.MonitorTimeframeParam.decade:
+ return format(setYear(time, which), "yyyy", { locale: locale6 });
+ }
+ assertUnreachable(timeframe);
+}
+function getTimeframesForDate(time, timeframe) {
+ switch (timeframe) {
+ case TalerCorebankApi.MonitorTimeframeParam.hour:
+ return {
+ current: getHours(sub(time, { hours: 1 })),
+ previous: getHours(sub(time, { hours: 2 }))
+ };
+ case TalerCorebankApi.MonitorTimeframeParam.day:
+ return {
+ current: getDate(sub(time, { days: 1 })),
+ previous: getDate(sub(time, { days: 2 }))
+ };
+ case TalerCorebankApi.MonitorTimeframeParam.month:
+ return {
+ current: getMonth(sub(time, { months: 1 })),
+ previous: getMonth(sub(time, { months: 2 }))
+ };
+ case TalerCorebankApi.MonitorTimeframeParam.year:
+ return {
+ current: getYear(sub(time, { years: 1 })),
+ previous: getYear(sub(time, { years: 2 }))
+ };
+ case TalerCorebankApi.MonitorTimeframeParam.decade:
+ return {
+ current: getYear(sub(time, { years: 10 })),
+ previous: getYear(sub(time, { years: 20 }))
+ };
+ default:
+ assertUnreachable(timeframe);
+ }
+}
+function Metrics({
+ routeDownloadStats
+}) {
+ const { i18n: i18n2, dateLocale } = useTranslationContext();
+ const [metricType, setMetricType] = p3(
+ TalerCorebankApi.MonitorTimeframeParam.hour
+ );
+ const { config } = useBankCoreApiContext();
+ const respInfo = useConversionInfo();
+ const params = getTimeframesForDate(/* @__PURE__ */ new Date(), metricType);
+ const resp = useLastMonitorInfo(params.current, params.previous, metricType);
+ if (!resp)
+ return /* @__PURE__ */ h(p2, null);
+ if (resp instanceof TalerError) {
+ return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: resp });
+ }
+ if (!respInfo)
+ return /* @__PURE__ */ h(p2, null);
+ if (respInfo instanceof TalerError) {
+ return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: respInfo });
+ }
+ if (respInfo.type === "fail") {
+ switch (respInfo.case) {
+ case HttpStatusCode.NotImplemented: {
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
+ }
+ default:
+ assertUnreachable(respInfo.case);
+ }
+ }
+ if (resp.current.type !== "ok" || resp.previous.type !== "ok") {
+ return /* @__PURE__ */ h(p2, null);
+ }
+ return /* @__PURE__ */ h("div", { class: "px-4 mt-4" }, /* @__PURE__ */ h("div", { class: "sm:flex sm:items-center mb-4" }, /* @__PURE__ */ h("div", { class: "sm:flex-auto" }, /* @__PURE__ */ h("h1", { class: "text-base font-semibold leading-6 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transaction volume report")))), /* @__PURE__ */ h("div", { class: "sm:hidden" }, /* @__PURE__ */ h("label", { for: "tabs", class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Select a section")), /* @__PURE__ */ h(
+ "select",
+ {
+ id: "tabs",
+ name: "tabs",
+ class: "block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500",
+ onChange: (e4) => {
+ setMetricType(
+ e4.currentTarget.value
+ );
+ }
+ },
+ /* @__PURE__ */ h(
+ "option",
+ {
+ value: TalerCorebankApi.MonitorTimeframeParam.hour,
+ selected: metricType == TalerCorebankApi.MonitorTimeframeParam.hour
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Last hour")
+ ),
+ /* @__PURE__ */ h(
+ "option",
+ {
+ value: TalerCorebankApi.MonitorTimeframeParam.day,
+ selected: metricType == TalerCorebankApi.MonitorTimeframeParam.day
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Previous day")
+ ),
+ /* @__PURE__ */ h(
+ "option",
+ {
+ value: TalerCorebankApi.MonitorTimeframeParam.month,
+ selected: metricType == TalerCorebankApi.MonitorTimeframeParam.month
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Last month")
+ ),
+ /* @__PURE__ */ h(
+ "option",
+ {
+ value: TalerCorebankApi.MonitorTimeframeParam.year,
+ selected: metricType == TalerCorebankApi.MonitorTimeframeParam.year
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Last year")
+ )
+ )), /* @__PURE__ */ h("div", { class: "hidden sm:block" }, /* @__PURE__ */ h(
+ "nav",
+ {
+ class: "isolate flex divide-x divide-gray-200 rounded-lg shadow",
+ "aria-label": "Tabs"
+ },
+ /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: "set last hour",
+ onClick: (e4) => {
+ e4.preventDefault();
+ setMetricType(TalerCorebankApi.MonitorTimeframeParam.hour);
+ },
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.hour,
+ class: "rounded-l-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
+ },
+ /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Last hour")),
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.hour,
+ class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
+ }
+ )
+ ),
+ /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: "set previous day",
+ onClick: (e4) => {
+ e4.preventDefault();
+ setMetricType(TalerCorebankApi.MonitorTimeframeParam.day);
+ },
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.day,
+ class: " text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
+ },
+ /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Previous day")),
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.day,
+ class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
+ }
+ )
+ ),
+ /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: "set last month",
+ onClick: (e4) => {
+ e4.preventDefault();
+ setMetricType(TalerCorebankApi.MonitorTimeframeParam.month);
+ },
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.month,
+ class: "rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
+ },
+ /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Last month")),
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.month,
+ class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
+ }
+ )
+ ),
+ /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: "set last year",
+ onClick: (e4) => {
+ e4.preventDefault();
+ setMetricType(TalerCorebankApi.MonitorTimeframeParam.year);
+ },
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.year,
+ class: "rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
+ },
+ /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Last Year")),
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-selected": metricType == TalerCorebankApi.MonitorTimeframeParam.year,
+ class: "bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
+ }
+ )
+ )
+ )), /* @__PURE__ */ h("div", { class: "w-full flex justify-between" }, /* @__PURE__ */ h("h1", { class: "text-base text-gray-900 mt-5" }, i18n2.str`Trading volume on ${getDateForTimeframe(
+ params.current,
+ metricType,
+ dateLocale
+ )} compared to ${getDateForTimeframe(
+ params.previous,
+ metricType,
+ dateLocale
+ )}`)), /* @__PURE__ */ h("dl", { class: "mt-5 grid grid-cols-1 md:grid-cols-2 divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0" }, resp.current.body.type !== "with-conversions" || resp.previous.body.type !== "with-conversions" ? void 0 : /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashin"), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from an external account to an account in this bank."))), /* @__PURE__ */ h(
+ MetricValue,
+ {
+ current: resp.current.body.cashinFiatVolume,
+ previous: resp.previous.body.cashinFiatVolume,
+ spec: respInfo.body.fiat_currency_specification
+ }
+ )), /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout")), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from an account in this bank to an external account.")), /* @__PURE__ */ h(
+ MetricValue,
+ {
+ current: resp.current.body.cashoutFiatVolume,
+ previous: resp.previous.body.cashoutFiatVolume,
+ spec: respInfo.body.fiat_currency_specification
+ }
+ ))), /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payin"), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from an account to a Taler exchange."))), /* @__PURE__ */ h(
+ MetricValue,
+ {
+ current: resp.current.body.talerInVolume,
+ previous: resp.previous.body.talerInVolume,
+ spec: config.currency_specification
+ }
+ )), /* @__PURE__ */ h("div", { class: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ h("dt", { class: "text-base font-normal text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payout"), /* @__PURE__ */ h("div", { class: "text-xs text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transferred from a Taler exchange to another account."))), /* @__PURE__ */ h(
+ MetricValue,
+ {
+ current: resp.current.body.talerOutVolume,
+ previous: resp.previous.body.talerOutVolume,
+ spec: config.currency_specification
+ }
+ ))), /* @__PURE__ */ h("div", { class: "flex justify-end mt-4" }, /* @__PURE__ */ h(
+ "a",
+ {
+ href: routeDownloadStats.url({}),
+ name: "download stats",
+ class: "disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Download stats as CSV")
+ )));
+}
+function MetricValue({
+ current,
+ previous,
+ spec
+}) {
+ const { i18n: i18n2 } = useTranslationContext();
+ const cmp = current && previous ? Amounts.cmp(current, previous) : 0;
+ const cv = !current ? void 0 : Amounts.stringifyValue(current);
+ const currAmount = !cv ? void 0 : Number.parseFloat(cv);
+ const prevAmount = !previous ? void 0 : Number.parseFloat(Amounts.stringifyValue(previous));
+ const rate = !currAmount || Number.isNaN(currAmount) || !prevAmount || Number.isNaN(prevAmount) ? 0 : cmp === -1 ? 1 - Math.round(currAmount) / Math.round(prevAmount) : cmp === 1 ? Math.round(currAmount) / Math.round(prevAmount) - 1 : 0;
+ const negative = cmp === 0 ? void 0 : cmp === -1;
+ const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`;
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("dd", { class: "mt-1 block " }, /* @__PURE__ */ h("div", { class: "flex justify-start text-2xl items-baseline font-semibold text-indigo-600" }, !current ? "-" : /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: Amounts.parseOrThrow(current),
+ spec,
+ hideSmall: true
+ }
+ )), /* @__PURE__ */ h("div", { class: "flex flex-col" }, /* @__PURE__ */ h("div", { class: "flex justify-end items-baseline text-2xl font-semibold text-indigo-600" }, /* @__PURE__ */ h("small", { class: "ml-2 text-sm font-medium text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "from"), " ", !previous ? "-" : /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: Amounts.parseOrThrow(previous),
+ spec,
+ hideSmall: true
+ }
+ ))), !!rate && /* @__PURE__ */ h(
+ "span",
+ {
+ "data-negative": negative,
+ class: "flex items-center gap-x-1.5 w-fit rounded-md bg-green-100 text-green-800 data-[negative=true]:bg-red-100 px-2 py-1 text-xs font-medium data-[negative=true]:text-red-700 whitespace-pre"
+ },
+ negative ? /* @__PURE__ */ h(
+ "svg",
+ {
+ xmlns: "http://www.w3.org/2000/svg",
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "1.5",
+ stroke: "currentColor",
+ class: "w-6 h-6"
+ },
+ /* @__PURE__ */ h(
+ "path",
+ {
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round",
+ d: "M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
+ }
+ )
+ ) : /* @__PURE__ */ h(
+ "svg",
+ {
+ xmlns: "http://www.w3.org/2000/svg",
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "1.5",
+ stroke: "currentColor",
+ class: "w-6 h-6"
+ },
+ /* @__PURE__ */ h(
+ "path",
+ {
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round",
+ d: "M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75"
+ }
+ )
+ ),
+ negative ? /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Decreased by")) : /* @__PURE__ */ h("span", { class: "sr-only" }, /* @__PURE__ */ h(i18n2.Translate, null, "Increased by")),
+ rateStr
+ ))));
+}
+
// src/pages/admin/CreateNewAccount.tsx
init_preact_module();
init_hooks_module();
@@ -36486,9 +36131,9 @@ function CreateNewAccount({
onCreateSuccess
}) {
const { i18n: i18n2 } = useTranslationContext();
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const token = credentials.status !== "loggedIn" ? void 0 : credentials.token;
- const { api } = useBankCoreApiContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
const [submitAccount, setSubmitAccount] = p3();
const [notification, notify2, handleError] = useLocalNotification();
async function doCreate() {
@@ -36508,70 +36153,80 @@ function CreateNewAccount({
type: "error",
title: i18n2.str`Server replied that phone or email is invalid`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Unauthorized:
return notify2({
type: "error",
title: i18n2.str`The rights to perform the operation are not sufficient`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
return notify2({
type: "error",
title: i18n2.str`Account username is already taken`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
return notify2({
type: "error",
title: i18n2.str`Account id is already taken`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return notify2({
type: "error",
title: i18n2.str`Bank ran out of bonus credit.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
return notify2({
type: "error",
title: i18n2.str`Account username can't be used because is reserved`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
return notify2({
type: "error",
title: i18n2.str`Only admin is allow to set debt limit.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_MISSING_TAN_INFO:
return notify2({
type: "error",
title: i18n2.str`No information for the selected authentication channel.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
return notify2({
type: "error",
title: i18n2.str`Authentication channel is not supported.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
return notify2({
type: "error",
title: i18n2.str`Only admin can create accounts with second factor authentication.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
default:
assertUnreachable(resp);
@@ -36590,7 +36245,7 @@ function CreateNewAccount({
/* @__PURE__ */ h(i18n2.Translate, null, "Close")
)));
}
- return /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "New bank account"))), /* @__PURE__ */ h(
+ return /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "New bank account"))), /* @__PURE__ */ h(
AccountForm,
{
template: void 0,
@@ -36624,6 +36279,431 @@ function CreateNewAccount({
));
}
+// src/pages/admin/DownloadStats.tsx
+init_preact_module();
+init_hooks_module();
+function DownloadStats({ routeCancel }) {
+ const { i18n: i18n2 } = useTranslationContext();
+ const { state: credentials } = useSessionState();
+ const creds = credentials.status !== "loggedIn" || !credentials.isUserAdministrator ? void 0 : credentials;
+ const { lib: { bank: api } } = useBankCoreApiContext();
+ const [options, setOptions] = p3({
+ compareWithPrevious: true,
+ dayMetric: true,
+ endOnFirstFail: false,
+ hourMetric: true,
+ includeHeader: true,
+ monthMetric: true,
+ yearMetric: true
+ });
+ const [lastStep, setLastStep] = p3();
+ const [downloaded, setDownloaded] = p3();
+ const referenceDates = [/* @__PURE__ */ new Date()];
+ const [notification, , handleError] = useLocalNotification();
+ if (!creds) {
+ return /* @__PURE__ */ h("div", null, "only admin can download stats");
+ }
+ return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Download bank stats"))), /* @__PURE__ */ h(
+ "form",
+ {
+ class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2",
+ autoCapitalize: "none",
+ autoCorrect: "off",
+ onSubmit: (e4) => {
+ e4.preventDefault();
+ }
+ },
+ /* @__PURE__ */ h("div", { class: "px-4 py-6 sm:p-8" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Include hour metric")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `hour switch`,
+ "data-enabled": options.hourMetric,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({
+ ...options,
+ hourMetric: !options.hourMetric
+ });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.hourMetric,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Include day metric")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `day switch`,
+ "data-enabled": !!options.dayMetric,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({ ...options, dayMetric: !options.dayMetric });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.dayMetric,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Include month metric")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `month switch`,
+ "data-enabled": !!options.monthMetric,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({
+ ...options,
+ monthMetric: !options.monthMetric
+ });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.monthMetric,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Include year metric")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `year switch`,
+ "data-enabled": !!options.yearMetric,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({
+ ...options,
+ yearMetric: !options.yearMetric
+ });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.yearMetric,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Include table header")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `header switch`,
+ "data-enabled": !!options.includeHeader,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({
+ ...options,
+ includeHeader: !options.includeHeader
+ });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.includeHeader,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Add previous metric for compare")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `compare switch`,
+ "data-enabled": !!options.compareWithPrevious,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({
+ ...options,
+ compareWithPrevious: !options.compareWithPrevious
+ });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.compareWithPrevious,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("div", { class: "flex items-center justify-between" }, /* @__PURE__ */ h("span", { class: "flex flex-grow flex-col" }, /* @__PURE__ */ h(
+ "span",
+ {
+ class: "text-sm text-black font-medium leading-6 ",
+ id: "availability-label"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Fail on first error")
+ )), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "button",
+ name: `fail switch`,
+ "data-enabled": !!options.endOnFirstFail,
+ class: "bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2",
+ role: "switch",
+ "aria-checked": "false",
+ "aria-labelledby": "availability-label",
+ "aria-describedby": "availability-description",
+ onClick: () => {
+ setOptions({
+ ...options,
+ endOnFirstFail: !options.endOnFirstFail
+ });
+ }
+ },
+ /* @__PURE__ */ h(
+ "span",
+ {
+ "aria-hidden": "true",
+ "data-enabled": options.endOnFirstFail,
+ class: "translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
+ }
+ )
+ ))))),
+ /* @__PURE__ */ h("div", { class: "flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8" }, /* @__PURE__ */ h(
+ "a",
+ {
+ name: "cancel",
+ href: routeCancel.url({}),
+ class: "text-sm font-semibold leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")
+ ), /* @__PURE__ */ h(
+ "button",
+ {
+ type: "submit",
+ name: "download",
+ class: "disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
+ disabled: lastStep !== void 0,
+ onClick: async () => {
+ setDownloaded(void 0);
+ await handleError(async () => {
+ const csv = await fetchAllStatus(
+ api,
+ creds.token,
+ options,
+ referenceDates,
+ (step, total) => {
+ setLastStep({ step, total });
+ }
+ );
+ setDownloaded(csv);
+ });
+ setLastStep(void 0);
+ }
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Download")
+ ))
+ )), !lastStep || lastStep.step === lastStep.total ? /* @__PURE__ */ h("div", { class: "h-5 mb-5" }) : /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "relative mb-5 h-5 rounded-full bg-gray-200" }, /* @__PURE__ */ h(
+ "div",
+ {
+ class: "h-full animate-pulse rounded-full bg-blue-500",
+ style: {
+ width: `${Math.round(lastStep.step / lastStep.total * 100)}%`
+ }
+ },
+ /* @__PURE__ */ h("span", { class: "absolute inset-0 flex items-center justify-center text-xs font-semibold text-white" }, /* @__PURE__ */ h(i18n2.Translate, null, "downloading...", " ", Math.round(lastStep.step / lastStep.total * 100)))
+ ))), !downloaded ? /* @__PURE__ */ h("div", { class: "h-5 mb-5" }) : /* @__PURE__ */ h(
+ "a",
+ {
+ href: "data:text/plain;charset=utf-8," + encodeURIComponent(downloaded),
+ name: "save file",
+ download: "bank-stats.csv"
+ },
+ /* @__PURE__ */ h(Attention, { title: i18n2.str`Download completed` }, /* @__PURE__ */ h(i18n2.Translate, null, "Click here to save the file in your computer."))
+ ));
+}
+async function fetchAllStatus(api, token, options, references, progress) {
+ const allMetrics = [];
+ if (options.hourMetric) {
+ allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.hour);
+ }
+ if (options.dayMetric) {
+ allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.day);
+ }
+ if (options.monthMetric) {
+ allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.month);
+ }
+ if (options.yearMetric) {
+ allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.year);
+ }
+ const allFrames = allMetrics.flatMap(
+ (timeframe) => references.map((reference) => ({
+ reference,
+ timeframe,
+ moment: getTimeframesForDate(reference, timeframe)
+ }))
+ );
+ const total = allFrames.length;
+ const allInfo = await allFrames.reduce(
+ async (prev, frame, index) => {
+ const accumulatedMap = await prev;
+ progress(index, total);
+ const previous = options.compareWithPrevious ? await api.getMonitor(token, {
+ timeframe: frame.timeframe,
+ which: frame.moment.previous
+ }) : void 0;
+ if (previous && previous.type === "fail" && options.endOnFirstFail) {
+ throw TalerError.fromUncheckedDetail(previous.detail);
+ }
+ const current = await api.getMonitor(token, {
+ timeframe: frame.timeframe,
+ which: frame.moment.current
+ });
+ if (current.type === "fail" && options.endOnFirstFail) {
+ throw TalerError.fromUncheckedDetail(current.detail);
+ }
+ const metricName = TalerCorebankApi.MonitorTimeframeParam[allMetrics[index]];
+ accumulatedMap[metricName] = {
+ reference: frame.reference,
+ current: current.type !== "ok" ? void 0 : current.body,
+ previous: !previous || previous.type !== "ok" ? void 0 : previous.body
+ };
+ return accumulatedMap;
+ },
+ Promise.resolve({})
+ );
+ progress(total, total);
+ const table2 = [];
+ if (options.includeHeader) {
+ table2.push([
+ "date",
+ "metric",
+ "reference",
+ "talerInCount",
+ "talerInVolume",
+ "talerOutCount",
+ "talerOutVolume",
+ "cashinCount",
+ "cashinFiatVolume",
+ "cashinRegionalVolume",
+ "cashoutCount",
+ "cashoutFiatVolume",
+ "cashoutRegionalVolume"
+ ]);
+ }
+ Object.entries(allInfo).forEach(([name, data]) => {
+ if (data.current) {
+ const row = {
+ date: data.reference.getTime(),
+ metric: name,
+ reference: "current",
+ ...dataToRow(data.current)
+ };
+ table2.push(Object.values(row));
+ }
+ if (data.previous) {
+ const row = {
+ date: data.reference.getTime(),
+ metric: name,
+ reference: "previous",
+ ...dataToRow(data.previous)
+ };
+ table2.push(Object.values(row));
+ }
+ });
+ const csv = table2.reduce((acc, row) => {
+ return acc + row.join(",") + "\n";
+ }, "");
+ return csv;
+}
+function dataToRow(info) {
+ return {
+ talerInCount: info.talerInCount,
+ talerInVolume: info.talerInVolume,
+ talerOutCount: info.talerOutCount,
+ talerOutVolume: info.talerOutVolume,
+ cashinCount: info.type === "no-conversions" ? void 0 : info.cashinCount,
+ cashinFiatVolume: info.type === "no-conversions" ? void 0 : info.cashinFiatVolume,
+ cashinRegionalVolume: info.type === "no-conversions" ? void 0 : info.cashinRegionalVolume,
+ cashoutCount: info.type === "no-conversions" ? void 0 : info.cashoutCount,
+ cashoutFiatVolume: info.type === "no-conversions" ? void 0 : info.cashoutFiatVolume,
+ cashoutRegionalVolume: info.type === "no-conversions" ? void 0 : info.cashoutRegionalVolume
+ };
+}
+
// src/pages/admin/RemoveAccount.tsx
init_preact_module();
init_hooks_module();
@@ -36638,9 +36718,9 @@ function RemoveAccount({
const { i18n: i18n2 } = useTranslationContext();
const result = useAccountDetails(account);
const [accountName, setAccountName] = p3();
- const { state } = useBackendState();
+ const { state } = useSessionState();
const token = state.status !== "loggedIn" ? void 0 : state.token;
- const { api } = useBankCoreApiContext();
+ const { lib: { bank: api } } = useBankCoreApiContext();
const [notification, notify2, handleError] = useLocalNotification();
const [, updateBankState] = useBankState();
if (!result) {
@@ -36690,28 +36770,32 @@ function RemoveAccount({
type: "error",
title: i18n2.str`No enough permission to delete the account.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`The username was not found.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
return notify2({
type: "error",
title: i18n2.str`Can't delete a reserved username.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case TalerErrorCode.BANK_ACCOUNT_BALANCE_NOT_ZERO:
return notify2({
type: "error",
title: i18n2.str`Can't delete an account with balance different than zero.`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.Accepted: {
updateBankState("currentChallenge", {
@@ -36740,7 +36824,7 @@ function RemoveAccount({
title: i18n2.str`You are going to remove the account`
},
/* @__PURE__ */ h(i18n2.Translate, null, "This step can't be undone.")
- ), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Deleting account "', account, '"'))), /* @__PURE__ */ h(
+ ), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, 'Deleting account "', account, '"'))), /* @__PURE__ */ h(
"form",
{
class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2",
@@ -36805,148 +36889,11 @@ function RemoveAccount({
)));
}
-// src/pages/business/ShowCashoutDetails.tsx
+// src/pages/regional/ConversionConfig.tsx
init_preact_module();
-function ShowCashoutDetails2({ id, routeClose }) {
- const { i18n: i18n2, dateLocale } = useTranslationContext();
- const cid = Number.parseInt(id, 10);
- const result = useCashoutDetails(Number.isNaN(cid) ? void 0 : cid);
- const info = useConversionInfo();
- if (Number.isNaN(cid)) {
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "danger",
- title: i18n2.str`Cashout id should be a number`
- }
- );
- }
- if (!result) {
- return /* @__PURE__ */ h(Loading, null);
- }
- if (result instanceof TalerError) {
- return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: result });
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.NotFound:
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "warning",
- title: i18n2.str`This cashout not found. Maybe already aborted.`
- }
- );
- case HttpStatusCode.NotImplemented:
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "warning",
- title: i18n2.str`Cashout are disabled`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.")
- );
- default:
- assertUnreachable(result);
- }
- }
- if (!info) {
- return /* @__PURE__ */ h(Loading, null);
- }
- if (info instanceof TalerError) {
- return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: info });
- }
- if (info.type === "fail") {
- switch (info.case) {
- case HttpStatusCode.NotImplemented: {
- return /* @__PURE__ */ h(
- Attention,
- {
- type: "danger",
- title: i18n2.str`Cashout are disabled`
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.")
- );
- }
- default:
- assertUnreachable(info.case);
- }
- }
- const { fiat_currency_specification, regional_currency_specification } = info.body;
- return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("section", { class: "rounded-sm px-4" }, /* @__PURE__ */ h("h2", { id: "summary-heading", class: "font-medium text-lg" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout detail")), /* @__PURE__ */ h("dl", { class: "mt-8 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex" }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Subject")), /* @__PURE__ */ h("dd", { class: "text-sm " }, result.body.subject)))), /* @__PURE__ */ h("div", { class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" }, /* @__PURE__ */ h("div", { class: "px-4 py-6 sm:p-8" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("dl", { class: "space-y-4" }, result.body.creation_time.t_s !== "never" ? /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: " text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Created")), /* @__PURE__ */ h("dd", { class: "text-sm " }, /* @__PURE__ */ h(
- Time,
- {
- format: "dd/MM/yyyy HH:mm:ss",
- timestamp: AbsoluteTime.fromProtocolTimestamp(result.body.creation_time)
- }
- ))) : void 0, /* @__PURE__ */ h("div", { class: "flex justify-between items-center border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Debited")), /* @__PURE__ */ h("dd", { class: " font-medium" }, /* @__PURE__ */ h(
- RenderAmount,
- {
- value: Amounts.parseOrThrow(result.body.amount_debit),
- negative: true,
- withColor: true,
- spec: regional_currency_specification
- }
- ))), /* @__PURE__ */ h("div", { class: "flex items-center justify-between border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "flex items-center text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Credited"))), /* @__PURE__ */ h("dd", { class: "text-sm " }, /* @__PURE__ */ h(
- RenderAmount,
- {
- value: Amounts.parseOrThrow(result.body.amount_credit),
- withColor: true,
- spec: fiat_currency_specification
- }
- ))))))))), /* @__PURE__ */ h("br", null), /* @__PURE__ */ h("div", { style: { display: "flex", justifyContent: "space-between" } }, /* @__PURE__ */ h(
- "a",
- {
- href: routeClose.url({}),
- name: "close",
- class: "text-sm font-semibold leading-6 text-gray-900"
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Close")
- )));
-}
-
-// src/route.ts
-function urlPattern(pattern, reverse) {
- const url = reverse;
- return {
- pattern: new RegExp(pattern),
- url
- };
-}
-var nullRountDef = {
- pattern: new RegExp(/.*/),
- url: () => ""
-};
-function findMatch(pagesMap, pageList, path, params) {
- for (let idx = 0; idx < pageList.length; idx++) {
- const name = pageList[idx];
- const found = pagesMap[name].pattern.exec(path);
- if (found !== null) {
- const values = {};
- Object.entries(params).forEach(([key, value]) => {
- values[key] = value;
- });
- if (found.groups !== void 0) {
- Object.entries(found.groups).forEach(([key, value]) => {
- values[key] = value;
- });
- }
- return { name, parent: pagesMap, values };
- }
- }
- return void 0;
-}
-function useCurrentLocation(pagesMap) {
- const pageList = Object.keys(pagesMap);
- const { path, params } = useNavigationContext();
- return findMatch(pagesMap, pageList, path, params);
-}
-
-// src/Routing.tsx
init_hooks_module();
-// src/pages/ConversionConfig.tsx
-init_preact_module();
+// src/hooks/form.ts
init_hooks_module();
function constructFormHandler(form, updateForm, errors2) {
const keys = Object.keys(form);
@@ -36962,7 +36909,9 @@ function constructFormHandler(form, updateForm, errors2) {
return prev;
}
const field = {
+ // @ts-expect-error FIXME better typing
error: currentError,
+ // @ts-expect-error FIXME better typing
value: currentValue,
onUpdate: updater
};
@@ -36977,8 +36926,9 @@ function useFormState(defaultValue, check) {
const handler = constructFormHandler(form, updateForm, status.errors);
return [handler, status];
}
+
+// src/pages/regional/ConversionConfig.tsx
function useComponentState5({
- onUpdateSuccess,
routeCancel,
routeConversionConfig,
routeMyAccountCashout,
@@ -36986,19 +36936,20 @@ function useComponentState5({
routeMyAccountDetails,
routeMyAccountPassword
}) {
+ const { i18n: i18n2 } = useTranslationContext();
const result = useConversionInfo();
const info = result && !(result instanceof TalerError) && result.type === "ok" ? result.body : void 0;
- const { state: credentials } = useBackendState();
+ const { state: credentials } = useSessionState();
const creds = credentials.status !== "loggedIn" || !credentials.isUserAdministrator ? void 0 : credentials;
if (!info) {
- return /* @__PURE__ */ h("div", null, "waiting...");
+ return /* @__PURE__ */ h(i18n2.Translate, null, "loading...");
}
if (!creds) {
- return /* @__PURE__ */ h("div", null, "only admin can setup conversion");
+ return /* @__PURE__ */ h(i18n2.Translate, null, "only admin can setup conversion");
}
- return () => {
- const { i18n: i18n2 } = useTranslationContext();
- const { api, config } = useBankCoreApiContext();
+ return function afterComponentLoads() {
+ const { i18n: i18n3 } = useTranslationContext();
+ const { lib: { conversion } } = useBankCoreApiContext();
const [notification, notify2, handleError] = useLocalNotification();
const initalState = {
amount: "100",
@@ -37017,14 +36968,10 @@ function useComponentState5({
};
const [form, status] = useFormState(
initalState,
- checkConversionForm(i18n2, info.regional_currency, info.fiat_currency)
+ createFormValidator(i18n3, info.regional_currency, info.fiat_currency)
);
- const {
- estimateByDebit: calculateCashoutFromDebit
- } = useCashoutEstimator();
- const {
- estimateByDebit: calculateCashinFromDebit
- } = useCashinEstimator();
+ const { estimateByDebit: calculateCashoutFromDebit } = useCashoutEstimator();
+ const { estimateByDebit: calculateCashinFromDebit } = useCashinEstimator();
const [calculationResult, setCalc] = p3();
h2(() => {
async function doAsync() {
@@ -37033,21 +36980,34 @@ function useComponentState5({
return;
if (!form.amount?.value || form.amount.error)
return;
- const in_amount = Amounts.parseOrThrow(`${info.fiat_currency}:${form.amount.value}`);
+ const in_amount = Amounts.parseOrThrow(
+ `${info.fiat_currency}:${form.amount.value}`
+ );
const in_fee = Amounts.parseOrThrow(info.conversion_rate.cashin_fee);
const cashin = await calculateCashinFromDebit(in_amount, in_fee);
if (cashin === "amount-is-too-small") {
setCalc(void 0);
return;
}
- const out_fee = Amounts.parseOrThrow(info.conversion_rate.cashout_fee);
- const cashout = await calculateCashoutFromDebit(cashin.credit, out_fee);
+ const out_fee = Amounts.parseOrThrow(
+ info.conversion_rate.cashout_fee
+ );
+ const cashout = await calculateCashoutFromDebit(
+ cashin.credit,
+ out_fee
+ );
setCalc({ cashin, cashout });
});
}
doAsync();
- }, [form.amount?.value, form.conv?.cashin_fee?.value, form.conv?.cashout_fee?.value]);
- const [section, setSection] = p3("detail");
+ }, [
+ form.amount?.value,
+ form.conv?.cashin_fee?.value,
+ form.conv?.cashout_fee?.value
+ ]);
+ const [section, setSection] = p3(
+ "detail"
+ );
const cashinCalc = calculationResult?.cashin === "amount-is-too-small" ? void 0 : calculationResult?.cashin;
const cashoutCalc = calculationResult?.cashout === "amount-is-too-small" ? void 0 : calculationResult?.cashout;
async function doUpdate() {
@@ -37056,7 +37016,10 @@ function useComponentState5({
await handleError(async () => {
if (status.status === "fail")
return;
- const resp = await api.getConversionInfoAPI().updateConversionRate(creds.token, status.result.conv);
+ const resp = await conversion.updateConversionRate(
+ creds.token,
+ status.result.conv
+ );
if (resp.type === "ok") {
setSection("detail");
} else {
@@ -37064,17 +37027,19 @@ function useComponentState5({
case HttpStatusCode.Unauthorized: {
return notify2({
type: "error",
- title: i18n2.str`Wrong credentials`,
+ title: i18n3.str`Wrong credentials`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
}
case HttpStatusCode.NotImplemented: {
return notify2({
type: "error",
- title: i18n2.str`Conversion is disabled`,
+ title: i18n3.str`Conversion is disabled`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
}
default:
@@ -37097,7 +37062,7 @@ function useComponentState5({
routeMyAccountPassword,
routeConversionConfig
}
- ), /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Conversion")), /* @__PURE__ */ h("div", { class: "px-2 mt-2 grid grid-cols-1 gap-y-4 sm:gap-x-4" }, /* @__PURE__ */ h(
+ ), /* @__PURE__ */ h(LocalNotificationBanner, { notification }), /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("div", { class: "px-4 sm:px-0" }, /* @__PURE__ */ h("h2", { class: "text-base font-semibold leading-7 text-gray-900" }, /* @__PURE__ */ h(i18n3.Translate, null, "Conversion")), /* @__PURE__ */ h("div", { class: "px-2 mt-2 grid grid-cols-1 gap-y-4 sm:gap-x-4" }, /* @__PURE__ */ h(
"label",
{
"data-enabled": section === "detail",
@@ -37117,7 +37082,7 @@ function useComponentState5({
}
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Details"))))
+ /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n3.Translate, null, "Details"))))
), /* @__PURE__ */ h(
"label",
{
@@ -37138,7 +37103,7 @@ function useComponentState5({
}
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Config cashout"))))
+ /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n3.Translate, null, "Config cashout"))))
), /* @__PURE__ */ h(
"label",
{
@@ -37159,7 +37124,7 @@ function useComponentState5({
}
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n2.Translate, null, "Config cashin"))))
+ /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900" }, /* @__PURE__ */ h(i18n3.Translate, null, "Config cashin"))))
))), /* @__PURE__ */ h(
"form",
{
@@ -37196,13 +37161,13 @@ function useComponentState5({
tiny: form?.conv?.cashout_tiny_amount
}
)),
- section == "detail" && /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashin ratio")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, info.conversion_rate.cashin_ratio))), /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout ratio")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, info.conversion_rate.cashout_ratio))), both_low || both_high ? /* @__PURE__ */ h("div", { class: "p-4" }, /* @__PURE__ */ h(Attention, { title: i18n2.str`Bad ratios`, type: "warning" }, /* @__PURE__ */ h(i18n2.Translate, null, "One of the ratios should be higher or equal than 1 an the other should be lower or equal than 1."))) : void 0, /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ section == "detail" && /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n3.Translate, null, "Cashin ratio")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, info.conversion_rate.cashin_ratio))), /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n3.Translate, null, "Cashout ratio")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, info.conversion_rate.cashout_ratio))), both_low || both_high ? /* @__PURE__ */ h("div", { class: "p-4" }, /* @__PURE__ */ h(Attention, { title: i18n3.str`Bad ratios`, type: "warning" }, /* @__PURE__ */ h(i18n3.Translate, null, "One of the ratios should be higher or equal than 1 an the other should be lower or equal than 1."))) : void 0, /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
"label",
{
for: "amount",
class: "block text-sm font-medium leading-6 text-gray-900"
},
- i18n2.str`Initial amount`
+ i18n3.str`Initial amount`
), /* @__PURE__ */ h(
InputAmount,
{
@@ -37218,7 +37183,7 @@ function useComponentState5({
message: form.amount?.error,
isDirty: form.amount?.value !== void 0
}
- ), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Use it to test how the conversion will affect the amount."))))), !cashoutCalc || !cashinCalc ? void 0 : /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("dl", { class: "mt-4 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Sending to this bank")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
+ ), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n3.Translate, null, "Use it to test how the conversion will affect the amount."))))), !cashoutCalc || !cashinCalc ? void 0 : /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("dl", { class: "mt-4 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n3.Translate, null, "Sending to this bank")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
RenderAmount,
{
value: cashinCalc.debit,
@@ -37226,20 +37191,20 @@ function useComponentState5({
withColor: true,
spec: info.regional_currency_specification
}
- ))), Amounts.isZero(cashinCalc.beforeFee) ? void 0 : /* @__PURE__ */ h("div", { class: "flex items-center justify-between afu " }, /* @__PURE__ */ h("dt", { class: "flex items-center text-sm text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Converted"))), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
+ ))), Amounts.isZero(cashinCalc.beforeFee) ? void 0 : /* @__PURE__ */ h("div", { class: "flex items-center justify-between afu " }, /* @__PURE__ */ h("dt", { class: "flex items-center text-sm text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n3.Translate, null, "Converted"))), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
RenderAmount,
{
value: cashinCalc.beforeFee,
spec: info.fiat_currency_specification
}
- ))), /* @__PURE__ */ h("div", { class: "flex justify-between items-center border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashin after fee")), /* @__PURE__ */ h("dd", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(
+ ))), /* @__PURE__ */ h("div", { class: "flex justify-between items-center border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(i18n3.Translate, null, "Cashin after fee")), /* @__PURE__ */ h("dd", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(
RenderAmount,
{
value: cashinCalc.credit,
withColor: true,
spec: info.fiat_currency_specification
}
- ))))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("dl", { class: "mt-4 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Sending from this bank")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
+ ))))), /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("dl", { class: "mt-4 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n3.Translate, null, "Sending from this bank")), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
RenderAmount,
{
value: cashoutCalc.debit,
@@ -37247,20 +37212,27 @@ function useComponentState5({
withColor: true,
spec: info.fiat_currency_specification
}
- ))), Amounts.isZero(cashoutCalc.beforeFee) ? void 0 : /* @__PURE__ */ h("div", { class: "flex items-center justify-between afu" }, /* @__PURE__ */ h("dt", { class: "flex items-center text-sm text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Converted"))), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
+ ))), Amounts.isZero(cashoutCalc.beforeFee) ? void 0 : /* @__PURE__ */ h("div", { class: "flex items-center justify-between afu" }, /* @__PURE__ */ h("dt", { class: "flex items-center text-sm text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n3.Translate, null, "Converted"))), /* @__PURE__ */ h("dd", { class: "text-sm text-gray-900" }, /* @__PURE__ */ h(
RenderAmount,
{
value: cashoutCalc.beforeFee,
spec: info.regional_currency_specification
}
- ))), /* @__PURE__ */ h("div", { class: "flex justify-between items-center border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout after fee")), /* @__PURE__ */ h("dd", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(
+ ))), /* @__PURE__ */ h("div", { class: "flex justify-between items-center border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(i18n3.Translate, null, "Cashout after fee")), /* @__PURE__ */ h("dd", { class: "text-lg text-gray-900 font-medium" }, /* @__PURE__ */ h(
RenderAmount,
{
value: cashoutCalc.credit,
withColor: true,
spec: info.regional_currency_specification
}
- ))))), cashoutCalc && status.status === "ok" && Amounts.cmp(status.result.amount, cashoutCalc.credit) < 0 ? /* @__PURE__ */ h("div", { class: "p-4" }, /* @__PURE__ */ h(Attention, { title: i18n2.str`Bad configuration`, type: "warning" }, /* @__PURE__ */ h(i18n2.Translate, null, "This configuration allows users to cash out more of what has been cashed in."))) : void 0)),
+ ))))), cashoutCalc && status.status === "ok" && Amounts.cmp(status.result.amount, cashoutCalc.credit) < 0 ? /* @__PURE__ */ h("div", { class: "p-4" }, /* @__PURE__ */ h(
+ Attention,
+ {
+ title: i18n3.str`Bad configuration`,
+ type: "warning"
+ },
+ /* @__PURE__ */ h(i18n3.Translate, null, "This configuration allows users to cash out more of what has been cashed in.")
+ )) : void 0)),
/* @__PURE__ */ h("div", { class: "flex items-center justify-between mt-4 gap-x-6 border-t border-gray-900/10 px-4 py-4" }, /* @__PURE__ */ h(
"a",
{
@@ -37268,7 +37240,7 @@ function useComponentState5({
href: routeCancel.url({}),
class: "text-sm font-semibold leading-6 text-gray-900"
},
- /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")
+ /* @__PURE__ */ h(i18n3.Translate, null, "Cancel")
), section == "cashin" || section == "cashout" ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(
"button",
{
@@ -37279,19 +37251,27 @@ function useComponentState5({
doUpdate();
}
},
- /* @__PURE__ */ h(i18n2.Translate, null, "Update")
+ /* @__PURE__ */ h(i18n3.Translate, null, "Update")
)) : /* @__PURE__ */ h("div", null))
)));
};
}
var ConversionConfig = utils_exports.recursive(useComponentState5);
-function checkConversionForm(i18n2, regional, fiat) {
+function createFormValidator(i18n2, regional, fiat) {
return function check(state) {
- const cashin_min_amount = Amounts.parse(`${fiat}:${state.conv.cashin_min_amount}`);
- const cashin_tiny_amount = Amounts.parse(`${regional}:${state.conv.cashin_tiny_amount}`);
+ const cashin_min_amount = Amounts.parse(
+ `${fiat}:${state.conv.cashin_min_amount}`
+ );
+ const cashin_tiny_amount = Amounts.parse(
+ `${regional}:${state.conv.cashin_tiny_amount}`
+ );
const cashin_fee = Amounts.parse(`${regional}:${state.conv.cashin_fee}`);
- const cashout_min_amount = Amounts.parse(`${regional}:${state.conv.cashout_min_amount}`);
- const cashout_tiny_amount = Amounts.parse(`${fiat}:${state.conv.cashout_tiny_amount}`);
+ const cashout_min_amount = Amounts.parse(
+ `${regional}:${state.conv.cashout_min_amount}`
+ );
+ const cashout_tiny_amount = Amounts.parse(
+ `${fiat}:${state.conv.cashout_tiny_amount}`
+ );
const cashout_fee = Amounts.parse(`${fiat}:${state.conv.cashout_fee}`);
const am = Amounts.parse(`${fiat}:${state.amount}`);
const cashin_ratio = Number.parseFloat(state.conv.cashin_ratio ?? "");
@@ -37329,19 +37309,28 @@ function checkConversionForm(i18n2, regional, fiat) {
return errors2 === void 0 ? { status: "ok", result, errors: errors2 } : { status: "fail", result, errors: errors2 };
};
}
-function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio, rounding, tiny }) {
+function ConversionForm({
+ id,
+ inputCurrency,
+ outputCurrency,
+ fee,
+ minimum,
+ ratio,
+ rounding,
+ tiny
+}) {
const { i18n: i18n2 } = useTranslationContext();
return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
"label",
{
- for: "cashin_min_amount",
+ for: `${id}_min_amount`,
class: "block text-sm font-medium leading-6 text-gray-900"
},
i18n2.str`Minimum amount`
), /* @__PURE__ */ h(
InputAmount,
{
- name: "cashin_min_amount",
+ name: `${id}_min_amount`,
left: true,
currency: inputCurrency,
value: minimum?.value ?? "",
@@ -37357,7 +37346,7 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
"label",
{
class: "block text-sm font-medium leading-6 text-gray-900",
- for: "password"
+ for: `${id}_ratio`
},
i18n2.str`Ratio`
), /* @__PURE__ */ h("div", { class: "mt-2" }, /* @__PURE__ */ h(
@@ -37366,7 +37355,7 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
type: "number",
class: "block rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6",
name: "current",
- id: "cashin_ratio",
+ id: `${id}_ratio`,
"data-error": !!ratio?.error && ratio?.value !== void 0,
value: ratio?.value ?? "",
onChange: (e4) => {
@@ -37383,14 +37372,14 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
)), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Conversion ratio between currencies"))), /* @__PURE__ */ h("div", { class: "px-6 pt-4" }, /* @__PURE__ */ h(Attention, { title: i18n2.str`Example conversion` }, /* @__PURE__ */ h(i18n2.Translate, null, "1 ", inputCurrency, " will be converted into ", ratio?.value, " ", outputCurrency))), /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
"label",
{
- for: "cashin_tiny_amount",
+ for: `${id}_tiny_amount`,
class: "block text-sm font-medium leading-6 text-gray-900"
},
i18n2.str`Rounding value`
), /* @__PURE__ */ h(
InputAmount,
{
- name: "cashin_tiny_amount",
+ name: `${id}_tiny_amount`,
left: true,
currency: outputCurrency,
value: tiny?.value ?? "",
@@ -37406,7 +37395,7 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
"label",
{
class: "block text-sm font-medium leading-6 text-gray-900",
- for: "channel"
+ for: `${id}_channel`
},
i18n2.str`Rounding mode`
), /* @__PURE__ */ h("div", { class: "mt-2 max-w-xl text-sm text-gray-500" }, /* @__PURE__ */ h("div", { class: "px-4 mt-4 grid grid-cols-1 gap-y-6" }, /* @__PURE__ */ h(
@@ -37428,14 +37417,7 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
class: "sr-only"
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-0-label",
- class: "block text-sm font-medium text-gray-900 "
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Zero")
- ), /* @__PURE__ */ h(i18n2.Translate, null, "Amount will be round below to the largest possible value smaller than the input."))),
+ /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900 " }, /* @__PURE__ */ h(i18n2.Translate, null, "Zero")), /* @__PURE__ */ h(i18n2.Translate, null, "Amount will be round below to the largest possible value smaller than the input."))),
/* @__PURE__ */ h(
"svg",
{
@@ -37473,14 +37455,7 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
class: "sr-only"
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-0-label",
- class: "block text-sm font-medium text-gray-900 "
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Up")
- ), /* @__PURE__ */ h(i18n2.Translate, null, "Amount will be round up to the smallest possible value larger than the input."))),
+ /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900 " }, /* @__PURE__ */ h(i18n2.Translate, null, "Up")), /* @__PURE__ */ h(i18n2.Translate, null, "Amount will be round up to the smallest possible value larger than the input."))),
/* @__PURE__ */ h(
"svg",
{
@@ -37518,14 +37493,7 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
class: "sr-only"
}
),
- /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h(
- "span",
- {
- id: "project-type-0-label",
- class: "block text-sm font-medium text-gray-900 "
- },
- /* @__PURE__ */ h(i18n2.Translate, null, "Nearest")
- ), /* @__PURE__ */ h(i18n2.Translate, null, "Amount will be round to the closest possible value."))),
+ /* @__PURE__ */ h("span", { class: "flex flex-1" }, /* @__PURE__ */ h("span", { class: "flex flex-col" }, /* @__PURE__ */ h("span", { class: "block text-sm font-medium text-gray-900 " }, /* @__PURE__ */ h(i18n2.Translate, null, "Nearest")), /* @__PURE__ */ h(i18n2.Translate, null, "Amount will be round to the closest possible value."))),
/* @__PURE__ */ h(
"svg",
{
@@ -37544,17 +37512,93 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
}
)
)
- )))))), /* @__PURE__ */ h("div", { class: "px-6 pt-4" }, /* @__PURE__ */ h(Attention, { title: i18n2.str`Examples` }, /* @__PURE__ */ h("section", { class: "grid grid-cols-1 gap-y-3 text-gray-600" }, /* @__PURE__ */ h("details", { class: "group text-sm" }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, "Rounding an amount of 1.24 with rounding value 0.1", /* @__PURE__ */ h("svg", { class: "h-6 w-6 rotate-0 transform group-open:rotate-180", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "2", stroke: "currentColor", "aria-hidden": "true" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M19 9l-7 7-7-7" }))), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, "Given the rounding value of 0.1 the possible values closest to 1.24 are: 1.1, 1.2, 1.3, 1.4."), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "zero" mode the value will be rounded to 1.2'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "nearest" mode the value will be rounded to 1.2'), /* @__PURE__ */ h("p", { class: "text-gray-900 mt-4" }, 'With the "up" mode the value will be rounded to 1.3')), /* @__PURE__ */ h("details", { class: "group " }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, "Rounding an amount of 1.26 with rounding value 0.1", /* @__PURE__ */ h("svg", { class: "h-6 w-6 rotate-0 transform group-open:rotate-180", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "2", stroke: "currentColor", "aria-hidden": "true" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M19 9l-7 7-7-7" }))), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, "Given the rounding value of 0.1 the possible values closest to 1.24 are: 1.1, 1.2, 1.3, 1.4."), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "zero" mode the value will be rounded to 1.2'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "nearest" mode the value will be rounded to 1.3'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "up" mode the value will be rounded to 1.3')), /* @__PURE__ */ h("details", { class: "group " }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, "Rounding an amount of 1.24 with rounding value 0.3", /* @__PURE__ */ h("svg", { class: "h-6 w-6 rotate-0 transform group-open:rotate-180", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "2", stroke: "currentColor", "aria-hidden": "true" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M19 9l-7 7-7-7" }))), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, "Given the rounding value of 0.3 the possible values closest to 1.24 are: 0.9, 1.2, 1.5, 1.8."), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "zero" mode the value will be rounded to 1.2'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "nearest" mode the value will be rounded to 1.2'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "up" mode the value will be rounded to 1.5')), /* @__PURE__ */ h("details", { class: "group " }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, "Rounding an amount of 1.26 with rounding value 0.3", /* @__PURE__ */ h("svg", { class: "h-6 w-6 rotate-0 transform group-open:rotate-180", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "2", stroke: "currentColor", "aria-hidden": "true" }, /* @__PURE__ */ h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M19 9l-7 7-7-7" }))), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, "Given the rounding value of 0.3 the possible values closest to 1.24 are: 0.9, 1.2, 1.5, 1.8."), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "zero" mode the value will be rounded to 1.2'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "nearest" mode the value will be rounded to 1.3'), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, 'With the "up" mode the value will be rounded to 1.3'))))), /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
+ )))))), /* @__PURE__ */ h("div", { class: "px-6 pt-4" }, /* @__PURE__ */ h(Attention, { title: i18n2.str`Examples` }, /* @__PURE__ */ h("section", { class: "grid grid-cols-1 gap-y-3 text-gray-600" }, /* @__PURE__ */ h("details", { class: "group text-sm" }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, /* @__PURE__ */ h(i18n2.Translate, null, "Rounding an amount of 1.24 with rounding value 0.1"), /* @__PURE__ */ h(
+ "svg",
+ {
+ class: "h-6 w-6 rotate-0 transform group-open:rotate-180",
+ xmlns: "http://www.w3.org/2000/svg",
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "2",
+ stroke: "currentColor",
+ "aria-hidden": "true"
+ },
+ /* @__PURE__ */ h(
+ "path",
+ {
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round",
+ d: "M19 9l-7 7-7-7"
+ }
+ )
+ )), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "Given the rounding value of 0.1 the possible values closest to 1.24 are: 1.1, 1.2, 1.3, 1.4.")), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "zero" mode the value will be rounded to 1.2')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "nearest" mode the value will be rounded to 1.2')), /* @__PURE__ */ h("p", { class: "text-gray-900 mt-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "up" mode the value will be rounded to 1.3'))), /* @__PURE__ */ h("details", { class: "group " }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, /* @__PURE__ */ h(i18n2.Translate, null, "Rounding an amount of 1.26 with rounding value 0.1"), /* @__PURE__ */ h(
+ "svg",
+ {
+ class: "h-6 w-6 rotate-0 transform group-open:rotate-180",
+ xmlns: "http://www.w3.org/2000/svg",
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "2",
+ stroke: "currentColor",
+ "aria-hidden": "true"
+ },
+ /* @__PURE__ */ h(
+ "path",
+ {
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round",
+ d: "M19 9l-7 7-7-7"
+ }
+ )
+ )), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "Given the rounding value of 0.1 the possible values closest to 1.24 are: 1.1, 1.2, 1.3, 1.4.")), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "zero" mode the value will be rounded to 1.2')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "nearest" mode the value will be rounded to 1.3')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "up" mode the value will be rounded to 1.3'))), /* @__PURE__ */ h("details", { class: "group " }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, /* @__PURE__ */ h(i18n2.Translate, null, "Rounding an amount of 1.24 with rounding value 0.3"), /* @__PURE__ */ h(
+ "svg",
+ {
+ class: "h-6 w-6 rotate-0 transform group-open:rotate-180",
+ xmlns: "http://www.w3.org/2000/svg",
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "2",
+ stroke: "currentColor",
+ "aria-hidden": "true"
+ },
+ /* @__PURE__ */ h(
+ "path",
+ {
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round",
+ d: "M19 9l-7 7-7-7"
+ }
+ )
+ )), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "Given the rounding value of 0.3 the possible values closest to 1.24 are: 0.9, 1.2, 1.5, 1.8.")), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "zero" mode the value will be rounded to 1.2')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "nearest" mode the value will be rounded to 1.2')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "up" mode the value will be rounded to 1.5'))), /* @__PURE__ */ h("details", { class: "group " }, /* @__PURE__ */ h("summary", { class: "flex cursor-pointer flex-row items-center justify-between " }, /* @__PURE__ */ h(i18n2.Translate, null, "Rounding an amount of 1.26 with rounding value 0.3"), /* @__PURE__ */ h(
+ "svg",
+ {
+ class: "h-6 w-6 rotate-0 transform group-open:rotate-180",
+ xmlns: "http://www.w3.org/2000/svg",
+ fill: "none",
+ viewBox: "0 0 24 24",
+ "stroke-width": "2",
+ stroke: "currentColor",
+ "aria-hidden": "true"
+ },
+ /* @__PURE__ */ h(
+ "path",
+ {
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round",
+ d: "M19 9l-7 7-7-7"
+ }
+ )
+ )), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "Given the rounding value of 0.3 the possible values closest to 1.24 are: 0.9, 1.2, 1.5, 1.8.")), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "zero" mode the value will be rounded to 1.2')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "nearest" mode the value will be rounded to 1.3')), /* @__PURE__ */ h("p", { class: "text-gray-900 my-4" }, /* @__PURE__ */ h(i18n2.Translate, null, 'With the "up" mode the value will be rounded to 1.3')))))), /* @__PURE__ */ h("div", { class: "px-6 pt-6" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h(
"label",
{
- for: "cashin_fee",
+ for: `${id}_fee`,
class: "block text-sm font-medium leading-6 text-gray-900"
},
i18n2.str`Fee`
), /* @__PURE__ */ h(
InputAmount,
{
- name: "cashin_fee",
+ name: `${id}_fee`,
left: true,
currency: outputCurrency,
value: fee?.value ?? "",
@@ -37569,18 +37613,113 @@ function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio
), /* @__PURE__ */ h("p", { class: "mt-2 text-sm text-gray-500" }, /* @__PURE__ */ h(i18n2.Translate, null, "Amount to be deducted before amount is credited."))))));
}
+// src/pages/regional/ShowCashoutDetails.tsx
+init_preact_module();
+function ShowCashoutDetails2({ id, routeClose }) {
+ const { i18n: i18n2 } = useTranslationContext();
+ const cid = Number.parseInt(id, 10);
+ const result = useCashoutDetails(Number.isNaN(cid) ? void 0 : cid);
+ const info = useConversionInfo();
+ if (Number.isNaN(cid)) {
+ return /* @__PURE__ */ h(
+ Attention,
+ {
+ type: "danger",
+ title: i18n2.str`Cashout id should be a number`
+ }
+ );
+ }
+ if (!result) {
+ return /* @__PURE__ */ h(Loading, null);
+ }
+ if (result instanceof TalerError) {
+ return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: result });
+ }
+ if (result.type === "fail") {
+ switch (result.case) {
+ case HttpStatusCode.NotFound:
+ return /* @__PURE__ */ h(
+ Attention,
+ {
+ type: "warning",
+ title: i18n2.str`This cashout not found. Maybe already aborted.`
+ }
+ );
+ case HttpStatusCode.NotImplemented:
+ return /* @__PURE__ */ h(Attention, { type: "warning", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
+ default:
+ assertUnreachable(result);
+ }
+ }
+ if (!info) {
+ return /* @__PURE__ */ h(Loading, null);
+ }
+ if (info instanceof TalerError) {
+ return /* @__PURE__ */ h(ErrorLoadingWithDebug, { error: info });
+ }
+ if (info.type === "fail") {
+ switch (info.case) {
+ case HttpStatusCode.NotImplemented: {
+ return /* @__PURE__ */ h(Attention, { type: "danger", title: i18n2.str`Cashout are disabled` }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode."));
+ }
+ default:
+ assertUnreachable(info.case);
+ }
+ }
+ const { fiat_currency_specification, regional_currency_specification } = info.body;
+ return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("div", { class: "grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg" }, /* @__PURE__ */ h("section", { class: "rounded-sm px-4" }, /* @__PURE__ */ h("h2", { id: "summary-heading", class: "font-medium text-lg" }, /* @__PURE__ */ h(i18n2.Translate, null, "Cashout detail")), /* @__PURE__ */ h("dl", { class: "mt-8 space-y-4" }, /* @__PURE__ */ h("div", { class: "justify-between items-center flex" }, /* @__PURE__ */ h("dt", { class: "text-sm text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Subject")), /* @__PURE__ */ h("dd", { class: "text-sm " }, result.body.subject)))), /* @__PURE__ */ h("div", { class: "bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" }, /* @__PURE__ */ h("div", { class: "px-4 py-6 sm:p-8" }, /* @__PURE__ */ h("div", { class: "grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" }, /* @__PURE__ */ h("div", { class: "sm:col-span-5" }, /* @__PURE__ */ h("dl", { class: "space-y-4" }, result.body.creation_time.t_s !== "never" ? /* @__PURE__ */ h("div", { class: "justify-between items-center flex " }, /* @__PURE__ */ h("dt", { class: " text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Created")), /* @__PURE__ */ h("dd", { class: "text-sm " }, /* @__PURE__ */ h(
+ Time,
+ {
+ format: "dd/MM/yyyy HH:mm:ss",
+ timestamp: AbsoluteTime.fromProtocolTimestamp(
+ result.body.creation_time
+ )
+ }
+ ))) : void 0, /* @__PURE__ */ h("div", { class: "flex justify-between items-center border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "text-gray-600" }, /* @__PURE__ */ h(i18n2.Translate, null, "Debited")), /* @__PURE__ */ h("dd", { class: " font-medium" }, /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: Amounts.parseOrThrow(result.body.amount_debit),
+ negative: true,
+ withColor: true,
+ spec: regional_currency_specification
+ }
+ ))), /* @__PURE__ */ h("div", { class: "flex items-center justify-between border-t-2 afu pt-4" }, /* @__PURE__ */ h("dt", { class: "flex items-center text-gray-600" }, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Credited"))), /* @__PURE__ */ h("dd", { class: "text-sm " }, /* @__PURE__ */ h(
+ RenderAmount,
+ {
+ value: Amounts.parseOrThrow(result.body.amount_credit),
+ withColor: true,
+ spec: fiat_currency_specification
+ }
+ ))))))))), /* @__PURE__ */ h("br", null), /* @__PURE__ */ h("div", { style: { display: "flex", justifyContent: "space-between" } }, /* @__PURE__ */ h(
+ "a",
+ {
+ href: routeClose.url({}),
+ name: "close",
+ class: "text-sm font-semibold leading-6 text-gray-900"
+ },
+ /* @__PURE__ */ h(i18n2.Translate, null, "Close")
+ )));
+}
+
// src/Routing.tsx
function Routing() {
- const backend = useBackendState();
- if (backend.state.status === "loggedIn") {
- const { isUserAdministrator, username } = backend.state;
- return /* @__PURE__ */ h(BankFrame, { account: username, routeAccountDetails: privatePages.myAccountDetails }, /* @__PURE__ */ h(PrivateRouting, { username, isAdmin: isUserAdministrator }));
+ const session = useSessionState();
+ if (session.state.status === "loggedIn") {
+ const { isUserAdministrator, username } = session.state;
+ return /* @__PURE__ */ h(
+ BankFrame,
+ {
+ account: username,
+ routeAccountDetails: privatePages.myAccountDetails
+ },
+ /* @__PURE__ */ h(PrivateRouting, { username, isAdmin: isUserAdministrator })
+ );
}
return /* @__PURE__ */ h(BankFrame, null, /* @__PURE__ */ h(
PublicRounting,
{
onLoggedUser: (username, token) => {
- backend.logIn({ username, token });
+ session.logIn({ username, token });
}
}
));
@@ -37598,11 +37737,10 @@ var publicPages = {
function PublicRounting({
onLoggedUser
}) {
- const settings = useSettingsContext();
const { i18n: i18n2 } = useTranslationContext();
const location2 = useCurrentLocation(publicPages);
const { navigateTo } = useNavigationContext();
- const { api } = useBankCoreApiContext();
+ const { config, lib } = useBankCoreApiContext();
const [notification, notify2, handleError] = useLocalNotification();
h2(() => {
if (location2 === void 0) {
@@ -37614,7 +37752,7 @@ function PublicRounting({
}
async function doAutomaticLogin(username, password) {
await handleError(async () => {
- const resp = await api.getAuthenticationAPI(username).createAccessToken(password, {
+ const resp = await lib.auth(username).createAccessToken(password, {
scope: "readwrite",
duration: { d_us: "forever" },
refreshable: true
@@ -37628,14 +37766,16 @@ function PublicRounting({
type: "error",
title: i18n2.str`Wrong credentials for "${username}"`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
case HttpStatusCode.NotFound:
return notify2({
type: "error",
title: i18n2.str`Account not found`,
description: resp.detail.hint,
- debug: resp.detail
+ debug: resp.detail,
+ when: AbsoluteTime.now()
});
default:
assertUnreachable(resp);
@@ -37645,7 +37785,7 @@ function PublicRounting({
}
switch (location2.name) {
case "login": {
- return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "sm:mx-auto sm:w-full sm:max-w-sm" }, /* @__PURE__ */ h("h2", { class: "text-center text-2xl font-bold leading-9 tracking-tight text-gray-900" }, i18n2.str`Welcome to ${settings.bankName}!`)), /* @__PURE__ */ h(LoginForm, { routeRegister: publicPages.register }));
+ return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "sm:mx-auto sm:w-full sm:max-w-sm" }, /* @__PURE__ */ h("h2", { class: "text-center text-2xl font-bold leading-9 tracking-tight text-gray-900" }, i18n2.str`Welcome to ${config.bank_name}!`)), /* @__PURE__ */ h(LoginForm, { routeRegister: publicPages.register }));
}
case "publicAccounts": {
return /* @__PURE__ */ h(PublicHistoriesPage, null);
@@ -37690,11 +37830,9 @@ var privatePages = {
/\/account\/charge-wallet/,
() => "#/account/charge-wallet"
),
- homeWireTransfer: urlPattern(
- /\/account\/wire-transfer/,
- () => "#/account/wire-transfer"
- ),
+ homeWireTransfer: urlPattern(/\/account\/wire-transfer/, () => "#/account/wire-transfer"),
home: urlPattern(/\/account/, () => "#/account"),
+ notifications: urlPattern(/\/notifications/, () => "#/notifications"),
solveSecondFactor: urlPattern(/\/2fa/, () => "#/2fa"),
cashoutCreate: urlPattern(/\/new-cashout/, () => "#/new-cashout"),
cashoutDetails: urlPattern(
@@ -38059,37 +38197,14 @@ function PrivateRouting({
}
);
}
+ case "notifications": {
+ return /* @__PURE__ */ h(ShowNotifications, null);
+ }
default:
assertUnreachable(location2);
}
}
-// src/context/backend.ts
-init_preact_module();
-init_hooks_module();
-var initial3 = {
- state: defaultState,
- logOut() {
- null;
- },
- expired() {
- null;
- },
- logIn(_info) {
- null;
- }
-};
-var Context7 = B(initial3);
-var BackendStateProvider = ({
- children
-}) => {
- const value = useBackendState();
- return h(Context7.Provider, {
- value,
- children
- });
-};
-
// src/i18n/strings.ts
var strings = {};
strings["it"] = {
@@ -40221,7 +40336,6 @@ strings["de"] = {
var defaultSettings = {
backendBaseURL: buildDefaultBackendBaseURL(),
iconLinkURL: void 0,
- bankName: "Taler Bank",
simplePasswordForRandomAccounts: false,
allowRandomAccountCreation: false,
topNavSites: {}
@@ -40229,7 +40343,7 @@ var defaultSettings = {
var codecForBankUISettings = () => buildCodecForObject().property("backendBaseURL", codecOptional(codecForString())).property("allowRandomAccountCreation", codecOptional(codecForBoolean())).property(
"simplePasswordForRandomAccounts",
codecOptional(codecForBoolean())
-).property("bankName", codecOptional(codecForString())).property("iconLinkURL", codecOptional(codecForString())).property("topNavSites", codecOptional(codecForMap(codecForString()))).build("BankUiSettings");
+).property("iconLinkURL", codecOptional(codecForString())).property("topNavSites", codecOptional(codecForMap(codecForString()))).build("BankUiSettings");
function removeUndefineField(obj) {
const keys = Object.keys(obj);
return keys.reduce((prev, cur) => {
@@ -40256,14 +40370,14 @@ function buildDefaultBackendBaseURL() {
window.location.pathname,
window.location.origin
).href;
- return currentLocation.replace("/webui", "");
+ return canonicalizeBaseUrl(currentLocation.replace("/webui", ""));
}
- return void 0;
+ throw Error("No default URL");
}
-// src/components/app.tsx
+// src/app.tsx
var WITH_LOCAL_STORAGE_CACHE = false;
-var App = () => {
+function App() {
const [settings, setSettings] = p3();
h2(() => {
fetchSettings(setSettings);
@@ -40280,7 +40394,10 @@ var App = () => {
de: strings["de"].completeness
}
},
- /* @__PURE__ */ h(BackendStateProvider, null, /* @__PURE__ */ h(BankCoreApiProvider, { baseUrl, frameOnError: BankFrame }, /* @__PURE__ */ h(
+ /* @__PURE__ */ h(BankApiProvider, { baseUrl: new URL("/", baseUrl), frameOnError: BankFrame, evictors: {
+ bank: evictBankSwrCache,
+ conversion: evictConversionSwrCache
+ } }, /* @__PURE__ */ h(
SWRConfig2,
{
value: {
@@ -40305,9 +40422,9 @@ var App = () => {
}
},
/* @__PURE__ */ h(TalerWalletIntegrationBrowserProvider, null, /* @__PURE__ */ h(BrowserHashNavigationProvider, null, /* @__PURE__ */ h(Routing, null)))
- )))
+ ))
));
-};
+}
window.setGlobalLogLevelFromString = setGlobalLogLevelFromString;
window.getGlobalLevel = getGlobalLogLevel;
function localStorageProvider() {
@@ -40318,7 +40435,6 @@ function localStorageProvider() {
});
return map2;
}
-var app_default = App;
function getInitialBackendBaseURL(backendFromSettings) {
const overrideUrl = typeof localStorage !== "undefined" ? localStorage.getItem("corebank-api-base-url") : void 0;
let result;
@@ -40340,12 +40456,78 @@ function getInitialBackendBaseURL(backendFromSettings) {
return canonicalizeBaseUrl(window.origin);
}
}
+var evictBankSwrCache = {
+ async notifySuccess(op) {
+ switch (op) {
+ case TalerCoreBankCacheEviction.DELETE_ACCOUNT: {
+ await Promise.all([
+ revalidatePublicAccounts(),
+ revalidateBusinessAccounts()
+ ]);
+ return;
+ }
+ case TalerCoreBankCacheEviction.CREATE_ACCOUNT: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateTransactions(),
+ revalidatePublicAccounts(),
+ revalidateBusinessAccounts()
+ ]);
+ return;
+ }
+ case TalerCoreBankCacheEviction.UPDATE_ACCOUNT: {
+ await Promise.all([revalidateAccountDetails()]);
+ return;
+ }
+ case TalerCoreBankCacheEviction.CREATE_TRANSACTION: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateTransactions()
+ ]);
+ return;
+ }
+ case TalerCoreBankCacheEviction.CONFIRM_WITHDRAWAL: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateTransactions()
+ ]);
+ return;
+ }
+ case TalerCoreBankCacheEviction.CREATE_CASHOUT: {
+ await Promise.all([
+ revalidateAccountDetails(),
+ revalidateCashouts(),
+ revalidateTransactions()
+ ]);
+ return;
+ }
+ case TalerCoreBankCacheEviction.UPDATE_PASSWORD:
+ case TalerCoreBankCacheEviction.ABORT_WITHDRAWAL:
+ case TalerCoreBankCacheEviction.CREATE_WITHDRAWAL:
+ return;
+ default:
+ assertUnreachable(op);
+ }
+ }
+};
+var evictConversionSwrCache = {
+ async notifySuccess(op) {
+ switch (op) {
+ case TalerBankConversionCacheEviction.UPDATE_RATE: {
+ await revalidateConversionInfo();
+ return;
+ }
+ default:
+ assertUnreachable(op);
+ }
+ }
+};
// src/index.tsx
init_preact_module();
var app = document.getElementById("app");
if (app) {
- P(/* @__PURE__ */ h(app_default, null), app);
+ P(/* @__PURE__ */ h(App, null), app);
} else {
console.error("HTML element with id 'app' not found.");
}