Skip to content

Commit 04da947

Browse files
committed
🩹 server: update card art
1 parent 672604e commit 04da947

5 files changed

Lines changed: 45 additions & 11 deletions

File tree

‎.changeset/curvy-cards.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@exactly/server": patch
3+
---
4+
5+
🩹 update card art

‎server/api/card.ts‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -597,12 +597,8 @@ This endpoint only accepts Wallet Extension bearer access. It does not accept \`
597597
if (kyc.applicationStatus !== "approved") {
598598
return c.json({ code: "kyc not approved" }, 403);
599599
}
600-
const productId =
601-
chain.id === base.id
602-
? credential.source === "5lu2sNu0v0ZElC2m77QR3rAZBHLr8PoG" // cspell:ignore azbh
603-
? SIGNATURE_PRODUCT_ID
604-
: BASE_PRODUCT_ID
605-
: SIGNATURE_PRODUCT_ID;
600+
const isCardArtOverride = credential.source === "5lu2sNu0v0ZElC2m77QR3rAZBHLr8PoG"; // cspell:ignore azbh
601+
const productId = chain.id === base.id && !isCardArtOverride ? BASE_PRODUCT_ID : SIGNATURE_PRODUCT_ID;
606602
const card = await getCards(pandaId)
607603
.then((pandaCards) => pandaCards.find(({ status }) => status === "active"))
608604
.then(async (orphan) => {
@@ -633,6 +629,7 @@ This endpoint only accepts Wallet Extension bearer access. It does not accept \`
633629
contexts: { details: { credentialId, scope: "cardLimit" } },
634630
});
635631
}),
632+
isCardArtOverride ? "c4c03256d6764a8390f41b60561d27af" : undefined,
636633
);
637634
}
638635
});

‎server/test/api/card.test.ts‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ describe("authenticated", () => {
10051005
const response = await appClient.index.$post({ header: { "test-credential-id": "base-default" } });
10061006

10071007
expect(response.status).toBe(200);
1008-
expect(createCard).toHaveBeenCalledWith("base-default-panda", BASE_PRODUCT_ID, undefined);
1008+
expect(createCard).toHaveBeenCalledWith("base-default-panda", BASE_PRODUCT_ID, undefined, undefined);
10091009
await expect(response.json()).resolves.toStrictEqual({
10101010
status: "ACTIVE",
10111011
lastFour: "4081",
@@ -1033,7 +1033,12 @@ describe("authenticated", () => {
10331033
const response = await appClient.index.$post({ header: { "test-credential-id": "base-signature" } });
10341034

10351035
expect(response.status).toBe(200);
1036-
expect(createCard).toHaveBeenCalledWith("base-signature-panda", SIGNATURE_PRODUCT_ID, undefined);
1036+
expect(createCard).toHaveBeenCalledWith(
1037+
"base-signature-panda",
1038+
SIGNATURE_PRODUCT_ID,
1039+
undefined,
1040+
"c4c03256d6764a8390f41b60561d27af",
1041+
);
10371042
await expect(response.json()).resolves.toStrictEqual({
10381043
status: "ACTIVE",
10391044
lastFour: "4242",
@@ -1061,7 +1066,7 @@ describe("authenticated", () => {
10611066
const response = await appClient.index.$post({ header: { "test-credential-id": "optimism-credential" } });
10621067

10631068
expect(response.status).toBe(200);
1064-
expect(createCard).toHaveBeenCalledWith("optimism-panda", SIGNATURE_PRODUCT_ID, undefined);
1069+
expect(createCard).toHaveBeenCalledWith("optimism-panda", SIGNATURE_PRODUCT_ID, undefined, undefined);
10651070
await expect(response.json()).resolves.toStrictEqual({
10661071
status: "ACTIVE",
10671072
lastFour: "1010",

‎server/test/utils/panda.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ describe("panda request", () => {
6666
});
6767

6868
describe("create card", () => {
69+
const customVirtualCardArt = "c4c03256d6764a8390f41b60561d27af";
6970
const card = {
7071
id: "card-id",
7172
userId: "user-id",
@@ -164,6 +165,30 @@ describe("create card", () => {
164165
}),
165166
);
166167
});
168+
169+
it("sends an explicit card art override", async () => {
170+
chainMock.id = base.id;
171+
const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValueOnce({
172+
ok: true,
173+
arrayBuffer: () => Promise.resolve(new TextEncoder().encode(JSON.stringify(card)).buffer),
174+
} as Response);
175+
176+
await expect(
177+
panda.createCard("user-id", SIGNATURE_PRODUCT_ID, 1_000_000, customVirtualCardArt),
178+
).resolves.toStrictEqual(card);
179+
expect(fetchSpy).toHaveBeenLastCalledWith(
180+
expect.stringContaining("/issuing/users/user-id/cards"),
181+
expect.objectContaining({
182+
method: "POST",
183+
body: JSON.stringify({
184+
type: "virtual",
185+
status: "active",
186+
limit: { amount: 1_000_000, frequency: "per7DayPeriod" },
187+
configuration: { productId: SIGNATURE_PRODUCT_ID, virtualCardArt: customVirtualCardArt },
188+
}),
189+
}),
190+
);
191+
});
167192
});
168193

169194
describe("siwe", () => {

‎server/utils/panda.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export async function createCard(
6868
userId: string,
6969
productId: typeof BASE_PRODUCT_ID | typeof PLATINUM_PRODUCT_ID | typeof SIGNATURE_PRODUCT_ID,
7070
amount = 1_000_000,
71+
virtualCardArt?: string,
7172
) {
7273
return await request(
7374
CardResponse,
@@ -80,13 +81,14 @@ export async function createCard(
8081
configuration: {
8182
productId,
8283
virtualCardArt:
83-
chain.id === baseSepolia.id || chain.id === optimismSepolia.id
84+
virtualCardArt ??
85+
(chain.id === baseSepolia.id || chain.id === optimismSepolia.id
8486
? "0c515d7eb0a140fa8f938f8242b0780a"
8587
: {
8688
[PLATINUM_PRODUCT_ID]: "81e42f27affd4e328f19651d4f2b438e",
8789
[SIGNATURE_PRODUCT_ID]: "398c4919514b4ec4927e6a9114a4c816",
8890
[BASE_PRODUCT_ID]: "79c1c868c3ae4b4dae2564295e75c357",
89-
}[productId],
91+
}[productId]),
9092
},
9193
}),
9294
"POST",

0 commit comments

Comments
 (0)