From ea58095ca121be302f0f75c2dfce35328e443ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadeusz=20Miesi=C4=85c?= <tadeusz.miesiac@gmail.com> Date: Fri, 22 Sep 2023 15:54:29 +0200 Subject: [PATCH] feat(top bar component init): added basic style, avarat and search input component --- .eslintrc.json | 3 +- jest.config.mjs => jest.config.ts | 2 ++ package.json | 6 ++-- setupTests.ts | 1 + src/assets/.gitkeep | 0 src/assets/images/user-avatar.png | Bin 0 -> 2627 bytes src/assets/vectors/icons/.gitkeep | 0 src/assets/vectors/icons/lens.svg | 10 ++++++ .../SearchBar/SearchBar.component.test.tsx | 15 +++++++++ .../TopBar/SearchBar/SearchBar.component.tsx | 30 ++++++++++++++++++ .../FunctionalArea/TopBar/SearchBar/index.ts | 1 + .../TopBar/TopBar.component.test.tsx | 13 ++++++++ .../TopBar/TopBar.component.tsx | 15 ++++++++- .../UserAvatar/UserAvatar.component.test.tsx | 12 +++++++ .../UserAvatar/UserAvatar.component.tsx | 8 +++++ .../FunctionalArea/TopBar/UserAvatar/index.ts | 1 + tsconfig.json | 10 +++++- 17 files changed, 121 insertions(+), 6 deletions(-) rename jest.config.mjs => jest.config.ts (90%) create mode 100644 setupTests.ts delete mode 100644 src/assets/.gitkeep create mode 100644 src/assets/images/user-avatar.png delete mode 100644 src/assets/vectors/icons/.gitkeep create mode 100644 src/assets/vectors/icons/lens.svg create mode 100644 src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx create mode 100644 src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx create mode 100644 src/components/FunctionalArea/TopBar/SearchBar/index.ts create mode 100644 src/components/FunctionalArea/TopBar/TopBar.component.test.tsx create mode 100644 src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.test.tsx create mode 100644 src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.tsx create mode 100644 src/components/FunctionalArea/TopBar/UserAvatar/index.ts diff --git a/.eslintrc.json b/.eslintrc.json index 9b67c6a2..94cbfd15 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -62,7 +62,8 @@ "test-*.{ts,tsx}", // repos with multiple top-level test files "**/*{.,_}{test,spec}.{ts,tsx}", // tests where the extension or filename suffix denotes that it is a test "**/jest.config.ts", // jest config - "**/jest.setup.ts" // jest setup + "**/jest.setup.ts", // jest setup + "**/setupTests.ts" ], "optionalDependencies": false } diff --git a/jest.config.mjs b/jest.config.ts similarity index 90% rename from jest.config.mjs rename to jest.config.ts index 2d42f861..7e7dad84 100644 --- a/jest.config.mjs +++ b/jest.config.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/extensions import nextJest from 'next/jest.js'; const createJestConfig = nextJest({ @@ -23,6 +24,7 @@ const config = { '!**/node_modules/**', ], coverageReporters: ['html', 'text', 'text-summary', 'cobertura'], + setupFilesAfterEnv: ['<rootDir>/setupTests.ts'], }; // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async diff --git a/package.json b/package.json index b4864fbb..a840cf2f 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ "lint:ts": "node_modules/eslint/bin/eslint.js src --ext .ts,.tsx", "prepare": "husky install", "postinstall": "husky install", - "test": "jest --watch --config ./jest.config.mjs", - "test:ci": "jest --config ./jest.config.mjs --collectCoverage --coverageDirectory=\"./coverage\" --ci --reporters=default --reporters=jest-junit --watchAll=false --passWithNoTests", - "test:coverage": "jest --watchAll --coverage --config ./jest.config.mjs", + "test": "jest --watch --config ./jest.config.ts", + "test:ci": "jest --config ./jest.config.ts --collectCoverage --coverageDirectory=\"./coverage\" --ci --reporters=default --reporters=jest-junit --watchAll=false --passWithNoTests", + "test:coverage": "jest --watchAll --coverage --config ./jest.config.ts", "test:coveragee": "jest --coverage", "coverage": "open ./coverage/lcov-report/index.html", "cypress": "cypress open" diff --git a/setupTests.ts b/setupTests.ts new file mode 100644 index 00000000..7b0828bf --- /dev/null +++ b/setupTests.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/assets/images/user-avatar.png b/src/assets/images/user-avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..3775ddea4346e27cc72a938e3bc1bedbe81f66ce GIT binary patch literal 2627 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 literal 0 HcmV?d00001 diff --git a/src/assets/vectors/icons/.gitkeep b/src/assets/vectors/icons/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/assets/vectors/icons/lens.svg b/src/assets/vectors/icons/lens.svg new file mode 100644 index 00000000..9e2627a9 --- /dev/null +++ b/src/assets/vectors/icons/lens.svg @@ -0,0 +1,10 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_2474_4682)"> +<path d="M12.0208 11.0767L14.8762 13.9314L13.9328 14.8747L11.0782 12.0194C10.016 12.8708 8.69483 13.334 7.3335 13.332C4.0215 13.332 1.3335 10.644 1.3335 7.33203C1.3335 4.02003 4.0215 1.33203 7.3335 1.33203C10.6455 1.33203 13.3335 4.02003 13.3335 7.33203C13.3354 8.69337 12.8723 10.0145 12.0208 11.0767ZM10.6835 10.582C11.5296 9.71196 12.0021 8.54565 12.0002 7.33203C12.0002 4.75336 9.9115 2.66536 7.3335 2.66536C4.75483 2.66536 2.66683 4.75336 2.66683 7.33203C2.66683 9.91003 4.75483 11.9987 7.3335 11.9987C8.54712 12.0006 9.71342 11.5281 10.5835 10.682L10.6835 10.582Z" fill="#6A6977"/> +</g> +<defs> +<clipPath id="clip0_2474_4682"> +<rect width="16" height="16" fill="white"/> +</clipPath> +</defs> +</svg> diff --git a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx new file mode 100644 index 00000000..b8f11bb2 --- /dev/null +++ b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.test.tsx @@ -0,0 +1,15 @@ +import { screen, render, RenderResult, fireEvent } from '@testing-library/react'; +import { SearchBar } from './SearchBar.component'; + +const renderComponent = (): RenderResult => render(<SearchBar />); + +describe('SearchBar - component', () => { + it('should let user type text', () => { + renderComponent(); + + const input = screen.getByRole('input', { name: 'search-input' }); + fireEvent.change(input, { target: { value: 'test value' } }); + + expect(screen.getByDisplayValue('test value')).toBeInTheDocument(); + }); +}); diff --git a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx new file mode 100644 index 00000000..82f82bb9 --- /dev/null +++ b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx @@ -0,0 +1,30 @@ +import Image from 'next/image'; +import { ChangeEvent, useState } from 'react'; +import lensIcon from '@/assets/vectors/icons/lens.svg'; + +export const SearchBar = (): JSX.Element => { + const [searchValue, setSearchValue] = useState<string>(''); + + const onSearchChange = (event: ChangeEvent<HTMLInputElement>): void => { + setSearchValue(event.target.value); + }; + + return ( + <div className="relative" data-testid="search-bar"> + <input + value={searchValue} + name="search-input" + aria-label="search-input" + onChange={onSearchChange} + className="bg-cultured r-[64px] w-72 rounded-[64px] py-2.5 px-4 text-xs outline-none border border-transparent focus:border-greyscale-600 hover:border-greyscale-600 font-medium text-font-400" + /> + <Image + src={lensIcon} + alt="lens icon" + height={16} + width={16} + className="absolute right-4 top-2.5" + /> + </div> + ); +}; diff --git a/src/components/FunctionalArea/TopBar/SearchBar/index.ts b/src/components/FunctionalArea/TopBar/SearchBar/index.ts new file mode 100644 index 00000000..e5d1538e --- /dev/null +++ b/src/components/FunctionalArea/TopBar/SearchBar/index.ts @@ -0,0 +1 @@ +export { SearchBar } from './SearchBar.component'; diff --git a/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx b/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx new file mode 100644 index 00000000..a611ffd3 --- /dev/null +++ b/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx @@ -0,0 +1,13 @@ +import { screen, render, RenderResult } from '@testing-library/react'; +import { TopBar } from './TopBar.component'; + +const renderComponent = (): RenderResult => render(<TopBar />); + +describe('TopBar - component', () => { + it('Should contain user avatar, search bar', () => { + renderComponent(); + + expect(screen.getByTestId('user-avatar')).toBeInTheDocument(); + expect(screen.getByTestId('search-bar')).toBeInTheDocument(); + }); +}); diff --git a/src/components/FunctionalArea/TopBar/TopBar.component.tsx b/src/components/FunctionalArea/TopBar/TopBar.component.tsx index fd98c130..a6929281 100644 --- a/src/components/FunctionalArea/TopBar/TopBar.component.tsx +++ b/src/components/FunctionalArea/TopBar/TopBar.component.tsx @@ -1 +1,14 @@ -export const TopBar = (): JSX.Element => <div className="w-100 bg-slate-600 h-16">.</div>; +import { SearchBar } from '@/components/FunctionalArea/TopBar/SearchBar'; +import { UserAvatar } from '@/components/FunctionalArea/TopBar/UserAvatar'; + +export const TopBar = (): JSX.Element => ( + <div className="w-100 bg-white h-16 flex flex-row items-center py-4 pl-7 pr-6 justify-between"> + <div className="flex flex-row items-center"> + <UserAvatar /> + <SearchBar /> + </div> + <div className="bg-primary-100 px-4 py-1 leading-6 text-xs text-primary-500"> + Parkinson disease map + </div> + </div> +); diff --git a/src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.test.tsx b/src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.test.tsx new file mode 100644 index 00000000..dbe50d02 --- /dev/null +++ b/src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.test.tsx @@ -0,0 +1,12 @@ +import { screen, render, RenderResult } from '@testing-library/react'; +import { UserAvatar } from './UserAvatar.component'; + +const renderComponent = (): RenderResult => render(<UserAvatar />); + +describe('UserAvatar - component ', () => { + it('should render placeholder image', () => { + renderComponent(); + + expect(screen.getByAltText('user avatar')).toBeInTheDocument(); + }); +}); diff --git a/src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.tsx b/src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.tsx new file mode 100644 index 00000000..c48e49cc --- /dev/null +++ b/src/components/FunctionalArea/TopBar/UserAvatar/UserAvatar.component.tsx @@ -0,0 +1,8 @@ +import Image from 'next/image'; +import avatarImg from '@/assets/images/user-avatar.png'; + +export const UserAvatar = (): JSX.Element => ( + <div className="w-8 h-8 mr-7" data-testid="user-avatar"> + <Image src={avatarImg} fill alt="user avatar" /> + </div> +); diff --git a/src/components/FunctionalArea/TopBar/UserAvatar/index.ts b/src/components/FunctionalArea/TopBar/UserAvatar/index.ts new file mode 100644 index 00000000..384816dc --- /dev/null +++ b/src/components/FunctionalArea/TopBar/UserAvatar/index.ts @@ -0,0 +1 @@ +export { UserAvatar } from './UserAvatar.component'; diff --git a/tsconfig.json b/tsconfig.json index 53d7a2e2..a44f42a5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,15 @@ "@/*": ["./src/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "pages"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "pages", + "jest.config.ts", + "setupTests.ts" + ], "exclude": ["node_modules", "cypress/**/*.ts", "cypress.config.ts"], "noFallthroughCasesInSwitch": true, //Ensures that any non-empty case inside a switch statement includes either break, return, or throw. "noImplicitReturns": true, // check all code paths in a function to ensure they return a value. -- GitLab