@remit/web-client 0.0.175 → 0.0.176
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/web-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.176",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Remit web client, published as composable primitives — the app shell, auth shells, and runtime config. A distributor imports what it composes and bundles it.",
|
|
6
6
|
"exports": {
|
|
@@ -3,6 +3,7 @@ import { type AddressEntry, ComposeAddressField } from "@remit/ui";
|
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
4
|
import { useMemo, useState } from "react";
|
|
5
5
|
import { useDebouncedValue } from "@/hooks/useDebouncedValue";
|
|
6
|
+
import { offerableAsRecipient } from "@/lib/recipient-suggestions";
|
|
6
7
|
|
|
7
8
|
export type { AddressEntry };
|
|
8
9
|
|
|
@@ -32,7 +33,7 @@ export const AddressField = ({
|
|
|
32
33
|
|
|
33
34
|
const suggestions = useMemo<AddressEntry[]>(
|
|
34
35
|
() =>
|
|
35
|
-
(data?.items ?? []).map((item) => ({
|
|
36
|
+
(data?.items ?? []).filter(offerableAsRecipient).map((item) => ({
|
|
36
37
|
email: item.normalizedEmail,
|
|
37
38
|
displayName: item.displayName,
|
|
38
39
|
})),
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import type { RemitImapAddressResponse } from "@remit/api-http-client";
|
|
4
|
+
import { offerableAsRecipient } from "./recipient-suggestions";
|
|
5
|
+
|
|
6
|
+
const setAt = 1;
|
|
7
|
+
|
|
8
|
+
const address = (
|
|
9
|
+
over: Partial<RemitImapAddressResponse> = {},
|
|
10
|
+
): RemitImapAddressResponse =>
|
|
11
|
+
({
|
|
12
|
+
normalizedEmail: "sales@pharma.example",
|
|
13
|
+
outboundCount: 0,
|
|
14
|
+
replyCount: 0,
|
|
15
|
+
flags: {},
|
|
16
|
+
...over,
|
|
17
|
+
}) as RemitImapAddressResponse;
|
|
18
|
+
|
|
19
|
+
describe("who the compose picker may offer", () => {
|
|
20
|
+
it("refuses a sender met only on mail in Junk", () => {
|
|
21
|
+
assert.equal(
|
|
22
|
+
offerableAsRecipient(
|
|
23
|
+
address({ flags: { junkOnly: { value: true, setAt } } }),
|
|
24
|
+
),
|
|
25
|
+
false,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("refuses a sender the account blocked", () => {
|
|
30
|
+
assert.equal(
|
|
31
|
+
offerableAsRecipient(
|
|
32
|
+
address({ flags: { blocked: { value: true, setAt } } }),
|
|
33
|
+
),
|
|
34
|
+
false,
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("refuses a blocked sender the search still has to return", () => {
|
|
39
|
+
assert.equal(
|
|
40
|
+
offerableAsRecipient(
|
|
41
|
+
address({
|
|
42
|
+
flags: {
|
|
43
|
+
junkOnly: { value: true, setAt },
|
|
44
|
+
blocked: { value: true, setAt },
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
),
|
|
48
|
+
false,
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("offers a muted sender, which is about notice and not about mail", () => {
|
|
53
|
+
assert.equal(
|
|
54
|
+
offerableAsRecipient(
|
|
55
|
+
address({ flags: { muted: { value: true, setAt } } }),
|
|
56
|
+
),
|
|
57
|
+
true,
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("offers a withheld sender the account has since sent mail to", () => {
|
|
62
|
+
assert.equal(
|
|
63
|
+
offerableAsRecipient(
|
|
64
|
+
address({
|
|
65
|
+
outboundCount: 1,
|
|
66
|
+
flags: { junkOnly: { value: true, setAt } },
|
|
67
|
+
}),
|
|
68
|
+
),
|
|
69
|
+
true,
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("offers a withheld sender the account has since replied to", () => {
|
|
74
|
+
assert.equal(
|
|
75
|
+
offerableAsRecipient(
|
|
76
|
+
address({ replyCount: 1, flags: { junkOnly: { value: true, setAt } } }),
|
|
77
|
+
),
|
|
78
|
+
true,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("offers a withheld sender the account has since named a VIP", () => {
|
|
83
|
+
assert.equal(
|
|
84
|
+
offerableAsRecipient(
|
|
85
|
+
address({
|
|
86
|
+
flags: {
|
|
87
|
+
junkOnly: { value: true, setAt },
|
|
88
|
+
vip: { value: true, setAt },
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
true,
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("offers a withheld sender the account has since trusted", () => {
|
|
97
|
+
assert.equal(
|
|
98
|
+
offerableAsRecipient(
|
|
99
|
+
address({
|
|
100
|
+
flags: {
|
|
101
|
+
junkOnly: { value: true, setAt },
|
|
102
|
+
trusted: { value: true, setAt },
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
),
|
|
106
|
+
true,
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RemitImapAddressResponse } from "@remit/api-http-client";
|
|
2
|
+
|
|
3
|
+
const accountHasCorresponded = (address: RemitImapAddressResponse): boolean =>
|
|
4
|
+
address.outboundCount > 0 ||
|
|
5
|
+
address.replyCount > 0 ||
|
|
6
|
+
address.flags?.vip?.value === true ||
|
|
7
|
+
address.flags?.trusted?.value === true;
|
|
8
|
+
|
|
9
|
+
export const offerableAsRecipient = (
|
|
10
|
+
address: RemitImapAddressResponse,
|
|
11
|
+
): boolean => {
|
|
12
|
+
if (address.flags?.blocked?.value === true) return false;
|
|
13
|
+
if (address.flags?.junkOnly?.value !== true) return true;
|
|
14
|
+
return accountHasCorresponded(address);
|
|
15
|
+
};
|