/*
This file is part of GNU Taler
(C) 2022 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see
*/
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { Props, State } from "./index.js";
import { buildTermsOfServiceState } from "./utils.js";
const supportedFormats = {
"text/html": "HTML",
"text/xml": "XML",
"text/markdown": "Markdown",
"text/plain": "Plain text",
"text/pdf": "PDF",
};
export function useComponentState({
showEvenIfaccepted,
exchangeUrl,
readOnly,
children,
}: Props): State {
const api = useBackendContext();
const [showContent, setShowContent] = useState(!!readOnly);
const { i18n, lang } = useTranslationContext();
const [forceAccepted, setForceAccepted] = useState();
const [tosLang, setTosLang] = useState();
const { pushAlertOnError } = useAlertContext();
const [format, setFormat] = useState("text/html");
const acceptedLang = tosLang ?? lang;
/**
* For the exchange selected, bring the status of the terms of service
*/
const terms = useAsyncAsHook(async () => {
const exchangeTos = await api.wallet.call(
WalletApiOperation.GetExchangeTos,
{
exchangeBaseUrl: exchangeUrl,
acceptedFormat: [format],
acceptLanguage: acceptedLang,
},
);
const supportedLangs = exchangeTos.tosAvailableLanguages.reduce(
(prev, cur) => {
prev[cur] = cur;
return prev;
},
{} as Record,
);
const state = buildTermsOfServiceState(exchangeTos);
return { state, supportedLangs };
}, [acceptedLang, format]);
if (!terms) {
return {
status: "loading",
error: undefined,
};
}
if (terms.hasError) {
return {
status: "error",
error: alertFromError(
i18n,
i18n.str`Could not load the status of the term of service`,
terms,
),
};
}
const { state, supportedLangs } = terms.response;
async function onUpdate(accepted: boolean): Promise {
if (!state) return;
if (accepted) {
await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
exchangeBaseUrl: exchangeUrl,
});
} else {
// mark as not accepted
}
terms?.retry();
}
const accepted = state.status === "accepted" || forceAccepted;
const base = {
error: undefined,
showingTermsOfService: {
value: showContent && (!accepted || showEvenIfaccepted),
button: {
onClick:
accepted && !showEvenIfaccepted
? undefined
: pushAlertOnError(async () => {
setShowContent(!showContent);
}),
},
},
terms: state,
termsAccepted: {
value: accepted,
button: {
onClick: readOnly
? undefined
: pushAlertOnError(async () => {
const newValue = !accepted; //toggle
await onUpdate(newValue);
setShowContent(false);
}),
},
},
};
if (accepted) {
return {
status: "show-buttons-accepted",
...base,
children,
};
}
if ((accepted && showEvenIfaccepted) || showContent) {
return {
status: "show-content",
error: undefined,
terms: state,
showingTermsOfService: readOnly ? undefined : base.showingTermsOfService,
termsAccepted: base.termsAccepted,
skipTos: {
onClick: pushAlertOnError(async () => {
setForceAccepted(true);
}),
},
tosFormat: {
onChange: pushAlertOnError(async (s) => {
setFormat(s);
}),
list: supportedFormats,
value: format ?? "",
},
tosLang: {
onChange: pushAlertOnError(async (s) => {
setTosLang(s);
}),
list: supportedLangs,
value: tosLang ?? lang,
},
};
}
//showing buttons
return {
status: "show-buttons-not-accepted",
...base,
};
}