Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

Commit

Permalink
fix: icon search page improvements (#9752)
Browse files Browse the repository at this point in the history
* feat: improving icons page  (#9655)

* feat:refactor icons page

* add ref in input element

* refactor icons page

* fix: icon search button

* fix: update tests

* fix: icon test to click button

* Update pages/icons.js

Co-authored-by: sital002 <[email protected]>

* Update pages/icons.js

---------

Co-authored-by: sital002 <[email protected]>
  • Loading branch information
eddiejaoude and sital002 authored Nov 11, 2023
1 parent 8b69061 commit fe1ed9e
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 67 deletions.
151 changes: 89 additions & 62 deletions pages/icons.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useMemo, useState } from "react";
import * as FaIcons from "react-icons/fa6";
import * as SiIcons from "react-icons/si";
import Input from "@components/form/Input";
Expand All @@ -7,65 +7,90 @@ import IconCard from "@components/IconCard";
import Page from "@components/Page";
import PageHead from "@components/PageHead";
import { PROJECT_NAME } from "@constants/index";
import { useRouter } from "next/router";
import Button from "@components/Button";

export default function Icons() {
const [searchedIconNames, setSearchedIconNames] = useState([]);
const [notFound, setNotFound] = useState();
const [threeOrMore, setThreeOrMore] = useState();
const icons = {};

const popularIcons = [
"FaGithub",
"FaTwitter",
"FaLinkedin",
"FaGit",
"FaXTwitter",
"FaInstagram",
"SiHashnode",
"FaLink",
"FaYoutube",
"FaGlobe",
"FaDev",
"FaDiscord",
"FaMedium",
"SiMedium",
"FaFacebook",
"FaGithubAlt",
"SiLinkedin",
"SiLeetcode",
"FaDollarSign",
"FaMastodon",
];
const icons = {};
Object.keys(FaIcons).forEach((key) => {
icons[key.toLocaleLowerCase()] = key;
});

Object.keys(FaIcons).forEach((key) => {
icons[key.toLocaleLowerCase()] = key;
});
Object.keys(SiIcons).forEach((key) => {
icons[key.toLocaleLowerCase()] = key;
});

Object.keys(SiIcons).forEach((key) => {
icons[key.toLocaleLowerCase()] = key;
});
const popularIcons = [
"FaGithub",
"FaTwitter",
"FaLinkedin",
"FaGit",
"FaXTwitter",
"FaInstagram",
"SiHashnode",
"FaLink",
"FaYoutube",
"FaGlobe",
"FaDev",
"FaDiscord",
"FaMedium",
"SiMedium",
"FaFacebook",
"FaGithubAlt",
"SiLinkedin",
"SiLeetcode",
"FaDollarSign",
"FaMastodon",
];

const searchIcons = (value) => {
setSearchedIconNames([]);
if (value.length < 3) {
return setThreeOrMore(false);
}
setThreeOrMore(true);
export default function Icons() {
const [notFound, setNotFound] = useState();

const filteredIconNames = Object.keys(icons)
.filter((icon) => icon.includes(value.toLocaleLowerCase()))
.map((iconName) => icons[iconName]);
if (!filteredIconNames.length) {
return setNotFound(value);
}
const router = useRouter();
const keyword = router.query.keyword || "";
const [threeOrMore, setThreeOrMore] = useState(
keyword.length >= 3 ? true : false,
);
const [searchQuery, setSearchQuery] = useState(keyword);

if (filteredIconNames.length) {
setNotFound();
const handleSubmit = (e) => {
e.preventDefault();
if (searchQuery === keyword) {
return;
}

setSearchedIconNames(filteredIconNames);
if (searchQuery.length === 0)
return router.replace({
pathname: "/icons",
});
router.replace({
pathname: "/icons",
query: { keyword: searchQuery },
});
};

const filterredIcons = useMemo(
(value = keyword) => {
if (value.length < 3) {
setThreeOrMore(false);
return popularIcons;
}
setThreeOrMore(true);

const filteredIconNames = Object.keys(icons)
.filter((icon) => icon.includes(value.toLocaleLowerCase()))
.map((iconName) => icons[iconName]);
if (!filteredIconNames.length) {
setNotFound(value);
return popularIcons;
}

if (filteredIconNames.length) {
setNotFound(false);
}
return filteredIconNames;
},
[keyword],
);
return (
<>
<PageHead
Expand All @@ -75,11 +100,15 @@ export default function Icons() {

<Page>
<h1 className="text-4xl mb-4 font-bold">Search For Icons</h1>
<Input
placeholder="Search Icons (minimum 3 characters)"
name="keyword"
onChange={(e) => searchIcons(e.target.value)}
/>
<form onSubmit={handleSubmit}>
<Input
placeholder="Search Icons (minimum 3 characters)"
value={searchQuery}
onChange={(e) => setSearchQuery(e.currentTarget.value)}
name="keyword"
/>
<Button>Search</Button>
</form>
{threeOrMore && notFound && (
<Alert type="error" message={`${notFound} not found`} />
)}
Expand All @@ -90,13 +119,11 @@ export default function Icons() {
/>
)}
<ul className="flex flex-wrap gap-4 mt-4">
{(searchedIconNames.length ? searchedIconNames : popularIcons).map(
(iconName, index) => (
<li key={index}>
<IconCard iconName={iconName} />
</li>
),
)}
{filterredIcons.map((iconName, index) => (
<li key={index}>
<IconCard iconName={iconName} />
</li>
))}
</ul>
</Page>
</>
Expand Down
38 changes: 33 additions & 5 deletions tests/icon.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

const defaultIcons = 20;

Expand All @@ -17,7 +18,7 @@ test("Icon search works correctly", async ({ page }) => {

// 3. type in search and check that icons with the name exist and check a name doesn't exist
const input = page.locator("[name='keyword']");
await input.type("mobile");
await input.fill("mobile");
const results = await page.locator("main ul li").count();

await expect(results).toBeGreaterThanOrEqual(7);
Expand All @@ -29,7 +30,7 @@ test("Icon search page has default results when no search term used", async ({
await page.goto("/icons");

const input = page.locator("[name='keyword']");
await input.type("");
await input.fill("");

await expect(page.locator("main ul li")).toHaveCount(defaultIcons);
});
Expand All @@ -40,7 +41,7 @@ test("Icon search page shows default results after typing 1 characters", async (
await page.goto("/icons");

const input = page.locator("[name='keyword']");
await input.type("e");
await input.fill("e");

await expect(page.locator("main ul li")).toHaveCount(defaultIcons);
});
Expand All @@ -51,9 +52,36 @@ test("Icon search page shows results after typing 3 characters", async ({
await page.goto("/icons");

const input = page.locator("[name='keyword']");
await input.type("hand");
await input.fill("hand");
await page.locator("form button").click();

await expect(page).toHaveURL("/icons?keyword=hand");
const results = await page.locator("main ul li").count();

await expect(page.locator("main ul li")).toContainText(["hand"]);
await expect(results).toBeGreaterThanOrEqual(defaultIcons);
expect(results).toBeGreaterThanOrEqual(defaultIcons);
});

test.describe("accessibility tests (dark)", () => {
test.use({ colorScheme: "dark" });

test("should pass axe wcag accessibility tests (_test-profile-user-6) (dark)", async ({
page,
}) => {
await page.goto("/_test-profile-user-6");
const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
.analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});

test("should pass axe wcag accessibility tests (_test-wcag-user) (dark)", async ({
page,
}) => {
await page.goto("/_test-wcag-user");
const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
.analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
});

0 comments on commit fe1ed9e

Please sign in to comment.