Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eager-snails-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

Gift cards filters now have option to filder by gift card code explicitly. Previously this was available only in search box, which uses `search` query, this however might not be available immediately after creating a gift card, due to indexing running in the background.
4 changes: 4 additions & 0 deletions playwright/pages/giftCardsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ExportGiftCardsDialog } from "@dialogs/exportGiftCardsDialog";
import { IssueGiftCardDialog } from "@dialogs/issueGiftCardDialog";
import { ResendGiftCardCodeDialog } from "@dialogs/resendGiftCardCodeDialog";
import { SetGiftCardsBalanceDialog } from "@dialogs/setGiftCardBalanceDialog";
import { FiltersPage } from "@pageElements/filtersPage";
import { MetadataSeoPage } from "@pageElements/metadataSeoPage";
import { BasePage } from "@pages/basePage";
import { expect, type Page } from "@playwright/test";
Expand All @@ -23,6 +24,8 @@ export class GiftCardsPage extends BasePage {

readonly setGiftCardsBalanceDialog: SetGiftCardsBalanceDialog;

readonly filtersPage!: FiltersPage;

constructor(
page: Page,
readonly issueCardButton = page.getByTestId("issue-card-button"),
Expand Down Expand Up @@ -55,6 +58,7 @@ export class GiftCardsPage extends BasePage {
this.deleteDialog = new DeleteDialog(page);
this.exportGiftCardsDialog = new ExportGiftCardsDialog(page);
this.setGiftCardsBalanceDialog = new SetGiftCardsBalanceDialog(page);
this.filtersPage = new FiltersPage(page);
}

async clickIssueCardButton() {
Expand Down
7 changes: 7 additions & 0 deletions playwright/pages/pageElements/filtersPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ export class FiltersPage extends BasePage {
await this.clickRightInput();
await this.dropDownOptions.filter({ hasText: channelName }).click();
}

async pickTextFilter(filterKind: string, value: string) {
await this.clickAddFilterButton();
await this.clickLeftInput();
await this.dropDownOptions.filter({ hasText: filterKind }).click();
await this.rightInput.fill(value);
}
}
4 changes: 3 additions & 1 deletion playwright/tests/giftCards.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@
await giftCardsPage.issueGiftCardDialog.clickOkButton();
await giftCardsPage.giftCardDialog.waitFor({ state: "hidden" });
await giftCardsPage.gotoGiftCardsListView();
await giftCardsPage.searchAndFindRowIndexes(fullCode);
await giftCardsPage.clickFilterButton();
await giftCardsPage.filtersPage.pickTextFilter("Code", fullCode);
await giftCardsPage.filtersPage.clickSaveFiltersButton();
expect(
await giftCardsPage.gridCanvas.locator("table tbody tr").count(),
"There should be only one gift card visible on list",
).toEqual(1);

Check failure on line 60 in playwright/tests/giftCards.spec.ts

View workflow job for this annotation

GitHub Actions / run-tests (1/2)

[e2e] › playwright/tests/giftCards.spec.ts:38:5 › TC: SALEOR_106 Issue gift card with specific customer and expiry date #e2e #gift

1) [e2e] › playwright/tests/giftCards.spec.ts:38:5 › TC: SALEOR_106 Issue gift card with specific customer and expiry date #e2e #gift Error: There should be only one gift card visible on list expect(received).toEqual(expected) // deep equality Expected: 1 Received: 0 58 | await giftCardsPage.gridCanvas.locator("table tbody tr").count(), 59 | "There should be only one gift card visible on list", > 60 | ).toEqual(1); | ^ 61 | }); 62 | test("TC: SALEOR_107 Resend code #e2e #gift", async () => { 63 | await giftCardsPage.clickListRowBasedOnContainingText(GIFT_CARDS.giftCardToResendCode.name); at /home/runner/work/saleor-dashboard/saleor-dashboard/playwright/tests/giftCards.spec.ts:60:5
});
test("TC: SALEOR_107 Resend code #e2e #gift", async () => {
await giftCardsPage.clickListRowBasedOnContainingText(GIFT_CARDS.giftCardToResendCode.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface InitialGiftCardsState {
isActive: ItemOption[];
tags: ItemOption[];
usedBy: ItemOption[];
code: ItemOption[];
}

export class InitialGiftCardsStateResponse implements InitialGiftCardsState {
Expand All @@ -16,6 +17,7 @@ export class InitialGiftCardsStateResponse implements InitialGiftCardsState {
public isActive: ItemOption[] = [],
public tags: ItemOption[] = [],
public usedBy: ItemOption[] = [],
public code: ItemOption[] = [],
) {}

public static empty() {
Expand Down Expand Up @@ -44,6 +46,8 @@ export class InitialGiftCardsStateResponse implements InitialGiftCardsState {
return this.tags;
case "usedBy":
return this.usedBy;
case "code":
return this.code;
default:
Comment on lines 47 to 51
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InitialGiftCardsStateResponse now supports resolving code tokens via getEntryByName, but the existing unit tests for filterByUrlToken() don’t cover this new case (they cover currency/tags/products/usedBy/isActive). Add a test for the code field to ensure URL rehydration works and to catch regressions when adjusting the code/giftCardCode naming.

Copilot uses AI. Check for mistakes.
return [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ export const useInitialGiftCardsState = () => {
const [loading, setLoading] = useState(true);
const queriesToRun: Array<Promise<InitialGiftCardsAPIResponse>> = [];

const fetchQueries = async ({ usedBy, products, currency, tags }: GiftCardsFetchingParams) => {
const fetchQueries = async ({
usedBy,
products,
currency,
tags,
code,
}: GiftCardsFetchingParams) => {
if (products.length > 0) {
queriesToRun.push(
client.query<_SearchProductOperandsQuery, _SearchProductOperandsQueryVariables>({
Expand Down Expand Up @@ -66,7 +72,7 @@ export const useInitialGiftCardsState = () => {
}

const data = await Promise.all(queriesToRun);
const initialState = createInitialGiftCardsState(data, tags);
const initialState = createInitialGiftCardsState(data, tags, code);

setData(
new InitialGiftCardsStateResponse(
Expand All @@ -75,6 +81,7 @@ export const useInitialGiftCardsState = () => {
initialState.isActive,
initialState.tags,
initialState.usedBy,
initialState.code,
),
);
setLoading(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ export const createInitialPageState = (data: InitialPageAPIResponse[]) =>
export const createInitialGiftCardsState = (
data: InitialGiftCardsAPIResponse[],
tags: string[],
code: string[],
): InitialGiftCardsState => {
return data.reduce(
(acc, query) => {
Expand Down Expand Up @@ -336,6 +337,7 @@ export const createInitialGiftCardsState = (
products: [],
tags: tags?.map(tag => ({ label: tag, value: tag, slug: tag })) ?? [],
usedBy: [],
code: code?.map(c => ({ label: c, value: c, slug: c })) ?? [],
} as InitialGiftCardsState,
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
CustomerHandler,
GiftCardTagsHandler,
type Handler,
NoopValuesHandler,
ProductsHandler,
} from "../Handler";
import { getFilterElement } from "../utils";
Expand Down Expand Up @@ -35,6 +36,10 @@ const createAPIHandler = (
return new CustomerHandler(client, inputValue);
}

if (rowType === "giftCardCode") {
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selectedRow.rowType() returns the filter element’s value.value (the left operand slug), which for the new filter is "code". Checking for "giftCardCode" here means this branch will never execute and the provider will throw Unknown filter element: "code" when the UI tries to load right-side options. Update this check (and any corresponding constants) so the rowType string matches what FilterElement.rowType() returns for this operand.

Suggested change
if (rowType === "giftCardCode") {
if (rowType === "code") {

Copilot uses AI. Check for mistakes.
return new NoopValuesHandler([]);
}

if (rowType === "isActive") {
return new BooleanValuesHandler([
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ describe("TokenArray / fetchingParams / getEmptyFetchingPrams", () => {
products: [],
tags: [],
usedBy: [],
code: [],
});
});

Expand Down Expand Up @@ -185,6 +186,7 @@ describe("TokenArray / fetchingParams / toGiftCardsFetchingParams", () => {
products: [],
tags: [],
usedBy: [],
code: [],
};

const token = {
Expand All @@ -203,6 +205,7 @@ describe("TokenArray / fetchingParams / toGiftCardsFetchingParams", () => {
products: ["product-1", "product-2", "product-3"],
tags: [],
usedBy: [],
code: [],
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface GiftCardsFetchingParams {
products: string[];
tags: string[];
usedBy: string[];
code: string[];
}

export interface CollectionFetchingParams {
Expand Down Expand Up @@ -137,6 +138,7 @@ const emptyGiftCardsFetchingParams: GiftCardsFetchingParams = {
products: [],
tags: [],
usedBy: [],
code: [],
};

const emptyCollectionFetchingParams: CollectionFetchingParams = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const VOUCHER_STATICS = ["channel", "discountType", "voucherStatus"];

const PAGE_STATIC = ["pageTypes"];

const GIFT_CARDS_STATICS = ["currency", "products", "isActive", "tags", "usedBy"];
const GIFT_CARDS_STATICS = ["currency", "products", "isActive", "tags", "usedBy", "code"];

const COLLECTION_STATICS = ["channel", "published"];

Expand Down
8 changes: 8 additions & 0 deletions src/components/ConditionalFilter/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const STATIC_CONDITIONS = {
isPreorder: [{ type: "select", label: "is", value: "input-1" }],
isGiftCardUsed: [{ type: "select", label: "is", value: "input-1" }],
isGiftCardBought: [{ type: "select", label: "is", value: "input-1" }],
giftCardCode: [{ type: "text", label: "is", value: "input-1" }],
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STATIC_CONDITIONS key is giftCardCode, but the gift card left operand uses slug: "code"/value: "code". URL tokens and FilterElement.rowType() use value.value (the slug), so this mismatch prevents the condition from being rehydrated from URL and can make the filter behave as "unknown". Align the static condition key with the URL/slug (e.g. use code as the STATIC_CONDITIONS key) so ConditionOptions.isStaticName(token.name) works for this filter.

Suggested change
giftCardCode: [{ type: "text", label: "is", value: "input-1" }],
code: [{ type: "text", label: "is", value: "input-1" }],

Copilot uses AI. Check for mistakes.
status: [
{
type: "combobox",
Expand Down Expand Up @@ -718,6 +719,13 @@ export const STATIC_GIFT_CARDS_OPTIONS: LeftOperand[] = [
type: "usedBy",
slug: "usedBy",
},
{
value: "code",
label: "Code",
type: "giftCardCode",
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This left-operand entry sets type: "giftCardCode" but slug/value: "code". Because FilterElement.rowType() returns value.value (the slug), the API provider / query builder will see this row as "code", not "giftCardCode", and ConditionOptions will also look up conditions by the slug when parsing URL tokens. Consider making type match the slug (e.g. type: "code") to keep the filter consistent end-to-end.

Suggested change
type: "giftCardCode",
type: "code",

Copilot uses AI. Check for mistakes.
slug: "code",
maxOccurrences: 1,
},
];

export const STATIC_CUSTOMER_OPTIONS: LeftOperand[] = [
Expand Down
Loading