From 67833e0d1c7cd123f63e762d2dc0e740ec0f2d4e Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 20 Feb 2024 16:06:48 +0100 Subject: [PATCH 1/2] categories dropdown --- package.json | 2 +- .../DropdownCategories/DropdownCategories.tsx | 190 ++++++++++++++++++ .../molecules/DropdownMenu/DropdownMenu.tsx | 11 +- .../{index.tsx => NewCourseCard.tsx} | 11 +- .../CourseCard/{index.tsx => CourseCard.tsx} | 11 +- src/index.ts | 6 +- 6 files changed, 203 insertions(+), 28 deletions(-) create mode 100644 src/components/molecules/DropdownCategories/DropdownCategories.tsx rename src/components/molecules/NewCourseCard/{index.tsx => NewCourseCard.tsx} (95%) rename src/components/skeletons/CourseCard/{index.tsx => CourseCard.tsx} (79%) diff --git a/package.json b/package.json index 244e1c6d..311d1dcf 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@types/react": "^17||^18", "@types/react-pdf": "^5.7.2", "@types/react-slick": "^0.23.8", - "@types/react-transition-group": "^4.4.5", + "@types/react-transition-group": "^4.4.10", "@types/styled-components": "^5.1.25", "@typescript-eslint/eslint-plugin": "^5.22.0", "@typescript-eslint/parser": "^5.22.0", diff --git a/src/components/molecules/DropdownCategories/DropdownCategories.tsx b/src/components/molecules/DropdownCategories/DropdownCategories.tsx new file mode 100644 index 00000000..4f42d841 --- /dev/null +++ b/src/components/molecules/DropdownCategories/DropdownCategories.tsx @@ -0,0 +1,190 @@ +import React, { FC, useRef, useState, useCallback, cloneElement } from "react"; +import { CSSTransition } from "react-transition-group"; +import styled, { withTheme } from "styled-components"; +import { useOnClickOutside } from "../../../hooks/useOnClickOutside"; +import { Checkbox } from "components/atoms/Option/Checkbox"; +import Text from "components/atoms/Typography/Text"; +import { Category } from "@escolalms/sdk/lib/types/api"; + +interface Props { + categories: Category[]; + checkedCategories: Category[]; + isInitiallyOpen?: boolean; + onChange: (category: Category) => void; + onClick?: () => void; + onClear?: () => void; + child?: React.ReactElement<{ onClick?: () => void; $isMenuOpen?: boolean }>; +} + +const Wrapper = styled.div` + position: relative; + width: max-content; + cursor: pointer; +`; + +const DropdownMenuWrapper = styled.ul` + top: 10px; + position: absolute; + left: 0; + z-index: 1000; + display: flex; + flex-direction: column; + width: max-content; + box-shadow: 0px 10px 15px #00000019; + min-width: 175px; + padding: 0px; + padding-bottom: 19px; + border: 1px solid ${({ theme }) => theme.gray3}; + background: ${({ theme }) => theme.white}; + border-radius: ${({ theme }) => theme.buttonRadius}px; + min-width: 300px; + &.fade-enter { + opacity: 0; + } + + &.fade-enter-active { + opacity: 1; + transition: 0.3s; + } + + &.fade-enter-done { + opacity: 1; + } + + &.fade-exit-active { + opacity: 0; + transition: 0.3s; + } +`; + +const MenuItem = styled.li` + display: flex; + padding: 0px 14px; + flex-direction: column; + &:not(&:last-child) { + margin-bottom: 20px; + } + > div { + display: flex; + flex-direction: column; + label { + font-size: 16px; + font-weight: 700; + } + } + .subcategories { + margin-top: 15px; + margin-left: 20px; + } +`; + +const ClearItem = styled.li` + display: flex; + justify-content: space-between; + margin-bottom: 20px; + border-bottom: 1px solid #eaeaea; + padding: 13px 14px; + p { + margin: 0; + } + button { + all: unset; + opacity: 0.55; + } +`; + +const DropdownCategoriesRecursive: FC< + Pick +> = ({ categories, checkedCategories, onChange }: Props) => { + const handleCategoryClick = (category: Category) => { + onChange(category); + }; + + return ( + <> + {categories.map((category: Category) => ( + + item.id === category.id) + ? true + : false + } + onChange={() => handleCategoryClick(category)} + /> + + {category.subcategories && category.subcategories.length > 0 && ( +
+ +
+ )} +
+ ))} + + ); +}; + +export const DropdownCategories: React.FC = ({ + child, + categories, + checkedCategories, + isInitiallyOpen, + onClick, + onChange, + onClear, +}) => { + const dropdownMenuRef = useRef(null); + const [isOpen, setIsOpen] = useState(isInitiallyOpen); + const closeMenu = () => setIsOpen(false); + useOnClickOutside(dropdownMenuRef, () => closeMenu()); + + const handleCategoryClick = useCallback( + (category: Category) => { + onChange?.(category); + }, + [onChange] + ); + + const handleClear = () => { + onClear?.(); + closeMenu(); + }; + + return ( + + {cloneElement(child as React.ReactElement, { + onClick: () => setIsOpen((prev) => !prev), + $isMenuOpen: isOpen, + })} + + + + Wybierz + + + + + + + ); +}; + +export default withTheme(DropdownCategories); diff --git a/src/components/molecules/DropdownMenu/DropdownMenu.tsx b/src/components/molecules/DropdownMenu/DropdownMenu.tsx index 67852be9..5c480ea5 100644 --- a/src/components/molecules/DropdownMenu/DropdownMenu.tsx +++ b/src/components/molecules/DropdownMenu/DropdownMenu.tsx @@ -18,6 +18,7 @@ interface Props { isInitiallyOpen?: boolean; onClick?: () => void; onChange?: (listItem: DropdownMenuItem) => void; + top?: number; } const Wrapper = styled.div` @@ -26,8 +27,8 @@ const Wrapper = styled.div` cursor: pointer; `; -const DropdownMenuWrapper = styled.ul` - top: 30px; +const DropdownMenuWrapper = styled.ul<{ $top?: number }>` + top: ${({ $top }) => ($top ? $top : 30)}px; position: absolute; left: 0; z-index: 1000; @@ -86,8 +87,8 @@ const DropdownMenu: FC = ({ isInitiallyOpen, onClick, onChange, + top, }) => { - // const [currID, setCurrID] = useState(0); const dropdownMenuRef = useRef(null); const [isOpen, setIsOpen] = useState(isInitiallyOpen); const closeMenu = () => setIsOpen(false); @@ -95,7 +96,6 @@ const DropdownMenu: FC = ({ const onListItemClick = useCallback( (ind: number) => { - // setCurrID(ind); onChange?.(menuItems[ind]); closeMenu(); }, @@ -107,7 +107,6 @@ const DropdownMenu: FC = ({ {cloneElement(child as React.ReactElement, { onClick: () => setIsOpen((prev) => !prev), $isMenuOpen: isOpen, - // children: isOpen ? "currID" : "Menu", })} = ({ classNames="fade" unmountOnExit > - + {menuItems.map(({ id, content }, index) => ( = (props) => { const { - id, mobile, title, image, @@ -264,13 +261,7 @@ export const NewCourseCard: React.FC = (props) => { ) )} -
- - - {title} - - -
+
{title}
{price} diff --git a/src/components/skeletons/CourseCard/index.tsx b/src/components/skeletons/CourseCard/CourseCard.tsx similarity index 79% rename from src/components/skeletons/CourseCard/index.tsx rename to src/components/skeletons/CourseCard/CourseCard.tsx index 1961831c..43919eab 100644 --- a/src/components/skeletons/CourseCard/index.tsx +++ b/src/components/skeletons/CourseCard/CourseCard.tsx @@ -3,9 +3,8 @@ import styled from "styled-components"; import "react-loading-skeleton/dist/skeleton.css"; import { useId } from "react"; import { Col, ScreenClass } from "react-grid-system"; -import { isMobile, isTablet } from "react-device-detect"; -const CardSkeleton = styled.div<{ $isMobile: boolean; $isTablet: boolean }>` +const CardSkeleton = styled.div` max-width: 278px; min-height: 414px; `; @@ -28,7 +27,7 @@ export const CourseCardSkeleton: React.FC = ({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - + = ({ ) : ( - + Date: Tue, 20 Feb 2024 16:08:16 +0100 Subject: [PATCH 2/2] categories dropdown --- .../molecules/DropdownCategories/DropdownCategories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/DropdownCategories/DropdownCategories.tsx b/src/components/molecules/DropdownCategories/DropdownCategories.tsx index 4f42d841..b8859b88 100644 --- a/src/components/molecules/DropdownCategories/DropdownCategories.tsx +++ b/src/components/molecules/DropdownCategories/DropdownCategories.tsx @@ -187,4 +187,4 @@ export const DropdownCategories: React.FC = ({ ); }; -export default withTheme(DropdownCategories); +export default withTheme(styled(DropdownCategories)``);