Vipps Donations #33

Merged
olaven merged 18 commits from vipps-demo into main 2024-08-24 16:55:08 +00:00
7 changed files with 27 additions and 23 deletions
Showing only changes of commit af99d4ec5a - Show all commits

View File

@ -4,7 +4,7 @@ type ButtonProps = {
children: ComponentChildren; children: ComponentChildren;
} & JSX.HTMLAttributes<HTMLButtonElement>; } & JSX.HTMLAttributes<HTMLButtonElement>;
const className = "p-2 border(gray-100 2) hover:bg-gray-200 bg-blue-200 w-max font-medium"; const className = "p-2 border(gray-100 2) hover:bg-gray-200 bg-blue-200 font-medium";
export function Button(props: ButtonProps) { export function Button(props: ButtonProps) {
const { children, className: additionalClass = "", ...buttonProps } = props; const { children, className: additionalClass = "", ...buttonProps } = props;

View File

@ -26,11 +26,11 @@ export const DonationSection = function () {
<p> <p>
Jeg ønsker at NRSS skal være gratis tilgjengelig for alle. Imidlertid koster det penger og tid å drifte og Jeg ønsker at NRSS skal være gratis tilgjengelig for alle. Imidlertid koster det penger og tid å drifte og
vedlikeholde en nettside. Dersom du har råd til det (og bare da!) setter jeg stor pris om du vil støtte vedlikeholde en nettside. Dersom du har råd til det (og bare da!) setter jeg stor pris om du vil støtte
prosjektet med et valgfritt, månedlig beløp via Vipps. prosjektet med et lite, månedlig beløp via Vipps.
</p> </p>
<div className="justify-center my-8"> <div className="justify-center my-8">
<form className={"flex"}> <form className={"flex flex-col mx-4"}>
<Input <Input
type={"email"} type={"email"}
placeholder={"din@epost.no"} placeholder={"din@epost.no"}
@ -43,6 +43,7 @@ export const DonationSection = function () {
<a <a
// don't navigate if email is not valid // don't navigate if email is not valid
href={emailInput ? `/api/trigger-donation/vipps?email=${emailInput}` : undefined} href={emailInput ? `/api/trigger-donation/vipps?email=${emailInput}` : undefined}
className={"mt-2"}
onClick={(e) => { onClick={(e) => {
if (!emailValid) { if (!emailValid) {
e.preventDefault(); e.preventDefault();
@ -70,18 +71,15 @@ export const DonationSection = function () {
> >
Eposten brukes utelukkende som referanse dersom du ønsker å avslutte støtten. Du kommer ikke til å motta Eposten brukes utelukkende som referanse dersom du ønsker å avslutte støtten. Du kommer ikke til å motta
noen eposter. noen eposter.
<b>
Du kan når som helst avslutte støtten fra{" "}
<a className="text-blue-600 underline" href="/donations-cancel">
denne siden
</a>.
</b>
</p> </p>
</div> </div>
<p>
<b>
Du kan når som helst avslutte støtten fra{" "}
<a className="text-blue-600 underline" href="/donations-cancel">
denne siden
</a>.
</b>
</p>
<p className="mt-4"> <p className="mt-4">
Opplever du problemer med betalingen, eller har du andre spørsmål? Ta{" "} Opplever du problemer med betalingen, eller har du andre spørsmål? Ta{" "}
<a className="text-blue-600 underline" href="mailto:olav@sundfoer.com"> <a className="text-blue-600 underline" href="mailto:olav@sundfoer.com">

View File

@ -31,5 +31,5 @@ Deno.test("generated rss contains promo with link to donations page", () => {
const feed = rss.assembleFeed(series); const feed = rss.assembleFeed(series);
console.log(feed); console.log(feed);
feed.includes("Vurder å støtte utviklingen via Vipps med valgfritt beløp"); feed.includes("Vurder å støtte utviklingen via Vipps");
}); });

View File

@ -59,7 +59,7 @@ function assembleFeed(series: Series): string {
function descriptionWithDonationPromotion(description: string): string { function descriptionWithDonationPromotion(description: string): string {
const promotion = const promotion =
`Takk for at du bruker NRSS 🙏🌟 Vurder å støtte utviklingen via Vipps med valgfritt beløp. Se mer på ${getHostUrl()}.`; `Takk for at du bruker NRSS 🙏🌟 Vurder å støtte utviklingen via Vipps med omtrent det samme som prisen på en kaffekopp. Se mer på ${getHostUrl()}.`;
return ` return `
--------------------------------\n --------------------------------\n

View File

@ -45,6 +45,7 @@ const getAccessToken = async function () {
export const createAgreement = async function (email: string) { export const createAgreement = async function (email: string) {
const token = await getAccessToken(); const token = await getAccessToken();
const amount = 5000; // 50 NOK
const response = await fetch(`${config.baseUrl}/recurring/v3/agreements/`, { const response = await fetch(`${config.baseUrl}/recurring/v3/agreements/`, {
method: "POST", method: "POST",
// @ts-ignore // @ts-ignore
@ -58,10 +59,14 @@ export const createAgreement = async function (email: string) {
"unit": "MONTH", "unit": "MONTH",
"count": 1, "count": 1,
}, },
"initialCharge": {
"amount": amount,
"description": "Initial charge",
"transactionType": "DIRECT_CAPTURE",
},
"pricing": { "pricing": {
"suggestedMaxAmount": 5000, // 50,- NOK "amount": amount,
"currency": "NOK", "currency": "NOK",
"type": "VARIABLE",
}, },
// email is used to identify the user in the success page // email is used to identify the user in the success page
"merchantRedirectUrl": `${getHostUrl()}/donations-success?email=${email}`, "merchantRedirectUrl": `${getHostUrl()}/donations-success?email=${email}`,

View File

@ -18,7 +18,7 @@ export const handler = async function (req: Request): Promise<Response> {
} }
const existingAgreement = await storage.readVippsAgreement({ id: email }); const existingAgreement = await storage.readVippsAgreement({ id: email });
if (existingAgreement) { if (existingAgreement && existingAgreement.revokedAt === null) {
console.error("Agreement already exists", email); console.error("Agreement already exists", email);
return Response.redirect(errorPage); return Response.redirect(errorPage);
} }

View File

@ -50,7 +50,7 @@ export default function ({ data }: PageProps<Props>) {
className={"p-4 mx-auto max-w-screen-md text-center"} className={"p-4 mx-auto max-w-screen-md text-center"}
> >
<h1 <h1
className={"text-4xl"} className={"text-3xl mb-6"}
> >
Avslutt støtte til NRSS Avslutt støtte til NRSS
</h1> </h1>
@ -63,21 +63,22 @@ export default function ({ data }: PageProps<Props>) {
</p> </p>
)} )}
{data.cancelled && ( {data.cancelled && (
<p> <p className={"text-left m-4"}>
Støtten er avsluttet. Tusen takk for at du har støttet NRSS 🙏🌟 Støtten er avsluttet. <br />
<b>Tusen takk for at du har støttet NRSS 🙏</b>
</p> </p>
)} )}
{!data.cancelled && ( {!data.cancelled && (
<form> <form className={"flex flex-col w-full"}>
<Input <Input
type={"email"} type={"email"}
placeholder={"din@epost.no"} placeholder={"din@epost.no"}
required required
name={"email"} name={"email"}
id={"email"} id={"email"}
> />
</Input>
<Button <Button
className={"w-full"}
type={"submit"} type={"submit"}
> >
Avslutt Avslutt