From fd567a3d608ad06aae9a2d5c69119002718e014c Mon Sep 17 00:00:00 2001 From: abhay Date: Sat, 27 Jul 2024 15:46:45 +0530 Subject: [PATCH 1/9] feat: implement the combo box for common and for endorsements page, correct the test to add combo box in the endorsements page --- __tests__/pages/endorsements.tests.tsx | 4 +- package.json | 3 + public/addicon.svg | 3 + public/downarrow.svg | 3 + src/components/Combobox/index.tsx | 77 +++++++++ src/components/SkillComboBox/index.tsx | 79 +++++++++ src/pages/endorsements/index.tsx | 22 ++- tailwind.config.js | 13 ++ yarn.lock | 225 +++++++++++++++++++++++++ 9 files changed, 422 insertions(+), 7 deletions(-) create mode 100644 public/addicon.svg create mode 100644 public/downarrow.svg create mode 100644 src/components/Combobox/index.tsx create mode 100644 src/components/SkillComboBox/index.tsx diff --git a/__tests__/pages/endorsements.tests.tsx b/__tests__/pages/endorsements.tests.tsx index 69224fd..4cc3dce 100644 --- a/__tests__/pages/endorsements.tests.tsx +++ b/__tests__/pages/endorsements.tests.tsx @@ -4,13 +4,15 @@ import { render, screen } from "@testing-library/react"; describe("Endorsements", () => { test("renders Endorsements ui", () => { render(); + const skillCombobox = screen.getByText("select skill"); const upvoteButton = screen.getByText("Upvote"); const downvoteButton = screen.getByText("Downvote"); const CompleteEndorsementButton = screen.getByText("Complete Endorsement"); - + expect(screen.getByText("Endorsements")).toBeInTheDocument(); expect(screen.getByText("search")).toBeInTheDocument(); expect(screen.getByTestId("input")).toBeInTheDocument(); + expect(skillCombobox).toBeInTheDocument(); expect(upvoteButton).toBeInTheDocument(); expect(downvoteButton).toBeInTheDocument(); expect(screen.getByPlaceholderText("placeholder text here")).toBeInTheDocument(); diff --git a/package.json b/package.json index 10ae3f4..358d5bb 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,15 @@ "test-watch": "jest --watch " }, "dependencies": { + "@headlessui/react": "^2.1.2", + "@heroicons/react": "^2.1.5", "@tanstack/react-query": "^4.33.0", "@tanstack/react-query-devtools": "^4.33.0", "@testing-library/react-hooks": "^8.0.1", "autoprefixer": "10.4.14", "axios": "^1.6.7", "classnames": "^2.5.1", + "clsx": "^2.1.1", "next": "13.4.4", "postcss": "8.4.23", "react": "18.2.0", diff --git a/public/addicon.svg b/public/addicon.svg new file mode 100644 index 0000000..9e54e97 --- /dev/null +++ b/public/addicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/downarrow.svg b/public/downarrow.svg new file mode 100644 index 0000000..6bca942 --- /dev/null +++ b/public/downarrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Combobox/index.tsx b/src/components/Combobox/index.tsx new file mode 100644 index 0000000..088bd2d --- /dev/null +++ b/src/components/Combobox/index.tsx @@ -0,0 +1,77 @@ +import Image from "next/image"; +import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'; +import clsx from 'clsx'; +import React, { useState, FC, ChangeEvent } from 'react'; + +type OptionTypes = { + id: number; + name: string; +}; + +type ComboboxProps = { + options: OptionTypes[]; + value: string; + onChange: (e: ChangeEvent) => void; + placeholder?: string; +} + +const ComboboxDropdown: FC = ({placeholder, options,value, onChange}: ComboboxProps) => { + const [query, setQuery] = useState(''); + + const filteredOptions = + query === '' + ? options + : options.filter((option) => { + return option?.name?.toLowerCase().includes(query.toLowerCase()) + }) + + return ( + setQuery('')}> +
+ option?.name} + onChange={(event) => setQuery(event.target.value)} + placeholder={placeholder} + /> + + expand + +
+ + + {filteredOptions?.length > 0 ? + + filteredOptions?.map((option) => ( + + {option?.name} + + )) :
+ + no results + +
} +
+
+ + ) +} + + +export default ComboboxDropdown; \ No newline at end of file diff --git a/src/components/SkillComboBox/index.tsx b/src/components/SkillComboBox/index.tsx new file mode 100644 index 0000000..9cd1325 --- /dev/null +++ b/src/components/SkillComboBox/index.tsx @@ -0,0 +1,79 @@ +import Image from "next/image"; +import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'; +import clsx from 'clsx'; +import React, { useState, FC, ChangeEvent } from 'react'; + +type OptionTypes = { + id: number; + skill: string; +}; + +type ComboboxProps = { + options: OptionTypes[]; + value: string; + onChange: (e: ChangeEvent) => void; + placeholder?: string; + handleAddSkill: () => void; +} + +const SkillCombobox: FC = ({placeholder, options,value, onChange, handleAddSkill}: ComboboxProps) => { + const [query, setQuery] = useState(''); + + const filteredSkills = + query === '' + ? options + : options.filter((option) => { + return option?.skill?.toLowerCase().includes(query.toLowerCase()) + }) + + return ( + setQuery('')}> +
+ option?.skill} + onChange={(event) => setQuery(event.target.value)} + placeholder={placeholder} + /> + + expand + +
+ + + {filteredSkills?.length > 0 ? + + filteredSkills?.map((option) => ( + + {option?.skill} + + )) :
+ + add skill icon + Add new skill + +
} +
+
+ + ) +} + + +export default SkillCombobox; \ No newline at end of file diff --git a/src/pages/endorsements/index.tsx b/src/pages/endorsements/index.tsx index f477975..e18d572 100644 --- a/src/pages/endorsements/index.tsx +++ b/src/pages/endorsements/index.tsx @@ -1,12 +1,23 @@ -import React, { FC } from "react"; -import { DropDown } from "@/components/DropDown"; +import React, { FC, useState } from "react"; import Layout from "@/components/Layout"; import SearchBox from "@/components/SearchBox"; import { BsHandThumbsUp, BsHandThumbsDown } from "react-icons/bs"; import SkillLabel from "@/components/SkillLabel"; -import { endorsementsListsMock } from "../../../__mocks__/endorsements"; +import { endorsementsListsMock, skillMockData } from "../../../__mocks__/endorsements"; +import SkillCombobox from "@/components/SkillComboBox"; const Endorsements: FC = () => { + + const [selected, setSelected] = useState(null); + + const handleSkillSelect = (value: string) => { + setSelected(value); + } + + const handleAddSkill = () => { + alert("Add skill clicked"); + } + return (
@@ -29,10 +40,9 @@ const Endorsements: FC = () => {

Prakash

-

skill:

- + +
-

vote: