~james/core

core/web/src/lib/components/profile/vouchRelationship.ts -rw-r--r-- 2.9 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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { didFromUri, rkeyFromUri } from "#lib/api/uri.ts";
import type { NetworkVouchItem, VouchKind } from "#lib/api/graph.ts";
import type { DirectVouch } from "#lib/components/profile/types.ts";

export interface VouchRelationship {
	viewer: string;
	actor: string;
	vouches: readonly NetworkVouchItem[];
}

export type VouchBadgeState =
	"direct-vouch" | "direct-denounce" | "mixed" | "indirect-vouch" | "indirect-denounce";

const incoming = ({ actor, vouches }: VouchRelationship) =>
	vouches.filter((vouch) => rkeyFromUri(vouch.uri) === actor);

const hasKind = (vouches: readonly NetworkVouchItem[], kind: VouchKind) =>
	vouches.some((vouch) => vouch.value.kind === kind);

export const isDirectVouch = (relationship: VouchRelationship): boolean =>
	incoming(relationship).some(
		(vouch) => didFromUri(vouch.uri) === relationship.viewer && vouch.value.kind === "vouch"
	);

export const isDirectDenounce = (relationship: VouchRelationship): boolean =>
	incoming(relationship).some(
		(vouch) => didFromUri(vouch.uri) === relationship.viewer && vouch.value.kind === "denounce"
	);

export const indirectVouches = (relationship: VouchRelationship): NetworkVouchItem[] =>
	incoming(relationship).filter((vouch) => didFromUri(vouch.uri) !== relationship.viewer);

export const isMixed = (relationship: VouchRelationship): boolean => {
	if (isDirectVouch(relationship) || isDirectDenounce(relationship)) return false;
	const vouches = indirectVouches(relationship);
	return hasKind(vouches, "vouch") && hasKind(vouches, "denounce");
};

export const isIndirectVouch = (relationship: VouchRelationship): boolean =>
	!isDirectVouch(relationship) &&
	!isDirectDenounce(relationship) &&
	hasKind(indirectVouches(relationship), "vouch");

export const isIndirectDenounce = (relationship: VouchRelationship): boolean =>
	!isDirectVouch(relationship) &&
	!isDirectDenounce(relationship) &&
	hasKind(indirectVouches(relationship), "denounce");

export const vouchStrength = (relationship: VouchRelationship): number =>
	indirectVouches(relationship).filter((vouch) => vouch.value.kind === "vouch").length;

export const denounceStrength = (relationship: VouchRelationship): number =>
	indirectVouches(relationship).filter((vouch) => vouch.value.kind === "denounce").length;

export const directVouch = (relationship: VouchRelationship): DirectVouch | null => {
	const own = incoming(relationship).find(
		(vouch) => didFromUri(vouch.uri) === relationship.viewer
	);
	return own
		? { kind: own.value.kind === "denounce" ? "denounce" : "vouch", reason: own.value.reason }
		: null;
};

export const vouchBadgeState = (relationship: VouchRelationship): VouchBadgeState | null => {
	if (isDirectVouch(relationship)) return "direct-vouch";
	if (isDirectDenounce(relationship)) return "direct-denounce";
	if (isMixed(relationship)) return "mixed";
	if (isIndirectVouch(relationship)) return "indirect-vouch";
	if (isIndirectDenounce(relationship)) return "indirect-denounce";
	return null;
};