~james/core

core/web/src/lib/api/newsletter.ts -rw-r--r-- 1.7 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 16 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { authedGet, authedPost, type DeliberiContext } from "#lib/api/deliberi.ts";
import { buildUrl, toResponseError } from "#lib/api/_request.ts";
import { nsidOf } from "#lib/api/syntax.ts";
import type { Fetch } from "#lib/fetch.ts";

const SIGNUP = nsidOf("org.tangled.temp.newsletter.signup");
const SUBSCRIBE = nsidOf("org.tangled.temp.account.subscribeNewsletter");
const DISMISS = nsidOf("org.tangled.temp.account.dismissNewsletter");
const GET_PREFERENCE = nsidOf("org.tangled.temp.account.getNewsletterPreference");

export type NewsletterStatus = "subscribed" | "dismissed";

const SIGNUP_FAILED = "Couldn't sign you up. Try again later.";

// open endpoint for signed-out visitors; signed-in accounts use subscribeNewsletter
export const signupNewsletter = async (
	serviceUrl: string,
	email: string,
	fetchFn: Fetch = fetch
): Promise<void> => {
	const response = await fetchFn(buildUrl(serviceUrl, SIGNUP), {
		method: "POST",
		headers: { "content-type": "application/json", accept: "application/json" },
		body: JSON.stringify({ email })
	}).catch(() => null);
	if (!response) throw new Error(SIGNUP_FAILED);
	if (response.ok) return;
	if (response.status < 500 && (await toResponseError(response)).error === "InvalidEmail") {
		throw new Error("Enter a valid email address.");
	}
	throw new Error(SIGNUP_FAILED);
};

export const getNewsletterStatus = async (
	ctx: DeliberiContext
): Promise<NewsletterStatus | undefined> =>
	(await authedGet<{ status?: NewsletterStatus }>(ctx, GET_PREFERENCE)).status;

export const subscribeNewsletter = (ctx: DeliberiContext): Promise<void> =>
	authedPost(ctx, SUBSCRIBE, null).then(() => undefined);

export const dismissNewsletter = (ctx: DeliberiContext): Promise<void> =>
	authedPost(ctx, DISMISS, null).then(() => undefined);