diff --git a/client/components/home/UserInput/Location/index.tsx b/client/components/home/UserInput/Location/index.tsx
index 9441f34..c608074 100644
--- a/client/components/home/UserInput/Location/index.tsx
+++ b/client/components/home/UserInput/Location/index.tsx
@@ -1,4 +1,4 @@
-import { Text } from "@chakra-ui/react";
+import { Box, Flex, Text } from "@chakra-ui/react";
import { fetchAddresses } from "api/onemap";
import { useUserInputs } from "hooks/useUserSelection";
import debounce from "lodash/debounce";
@@ -10,9 +10,10 @@ import { AddressOption } from "app-context/UserSelectionContext/types";
interface LocationProps {
handleBlur?: () => void;
showText: boolean;
+ containerStyle?: React.CSSProperties;
}
-export const Location = ({ handleBlur, showText }: LocationProps) => {
+export const Location = ({ handleBlur, showText, containerStyle = {} }: LocationProps) => {
const [showEmptyWarning, setShowEmptyWarning] = useState(false);
const { address, setAddress } = useUserInputs();
const { value: addressValue } = address;
@@ -46,7 +47,7 @@ export const Location = ({ handleBlur, showText }: LocationProps) => {
}, [addressValue]);
return (
-
+
{showText && (
Where are you at?
@@ -66,6 +67,10 @@ export const Location = ({ handleBlur, showText }: LocationProps) => {
setShowEmptyWarning(false);
}}
styles={{
+ container: (base) => ({
+ ...base,
+ ...containerStyle,
+ }),
control: (base) => ({
...base,
overflow: "hidden",
@@ -89,6 +94,6 @@ export const Location = ({ handleBlur, showText }: LocationProps) => {
handleShowError();
}}
/>
-
+
);
};
diff --git a/client/components/map/Buttons.tsx b/client/components/map/Buttons.tsx
index 67562c4..649d194 100644
--- a/client/components/map/Buttons.tsx
+++ b/client/components/map/Buttons.tsx
@@ -1,22 +1,34 @@
-import { HamburgerIcon, Search2Icon, CloseIcon } from "@chakra-ui/icons";
+import { Search2Icon, CloseIcon } from "@chakra-ui/icons";
import { MouseEventHandler } from "react";
-import { IconButton } from "@chakra-ui/react";
+import { Icon, IconButton } from "@chakra-ui/react";
import { COLORS } from "theme";
interface ButtonProps {
onClick: MouseEventHandler;
+ height?: string;
}
// Button Design for the filter button
-export const FilterButton = ({ onClick }: ButtonProps) => {
+export const FilterButton = ({ onClick, height }: ButtonProps) => {
return (
}
+ icon={
+
+
+
+ }
onClick={onClick}
+ height={height}
/>
);
};
diff --git a/client/components/map/FilterPanel.tsx b/client/components/map/FilterPanel.tsx
index 3b7bf5d..e4f8ac1 100644
--- a/client/components/map/FilterPanel.tsx
+++ b/client/components/map/FilterPanel.tsx
@@ -1,117 +1,245 @@
import {
Box,
- VStack,
HStack,
- Spacer,
- Button,
Text,
Slider,
SliderTrack,
SliderFilledTrack,
SliderThumb,
+ Modal,
+ ModalContent,
+ ModalOverlay,
Divider,
- CheckboxGroup,
- Checkbox,
- Stack,
+ Button,
+ Flex,
+ useCheckbox,
+ chakra,
+ CheckboxProps,
+ useCheckboxGroup,
+ Spacer,
+ useRadio,
+ UseRadioProps,
+ useRadioGroup,
} from "@chakra-ui/react";
-import { XButton } from "./Buttons";
import { COLORS } from "theme";
import { TItemSelection, TEmptyItem } from "app-context/SheetyContext/types";
import { OptionType } from "spa-pages";
-import { ChangeEvent } from "react";
+import React, { ChangeEvent, PropsWithChildren } from "react";
+import { Methods } from "api/sheety/enums";
type FilterProps = {
- isMobile: boolean | undefined;
- setFilterShow: () => void;
+ isOpen: boolean;
filterApply: () => void;
handleSliderChange: (val: number) => void;
range: number;
itemState: (TItemSelection | TEmptyItem)[];
selectOptions: OptionType[];
handleCheckboxChange: (e: ChangeEvent) => void;
+ selectAllItems: () => void;
};
export const FilterPanel = ({
- isMobile,
- setFilterShow,
+ isOpen,
filterApply,
handleSliderChange,
range,
itemState,
selectOptions,
handleCheckboxChange,
+ selectAllItems,
}: FilterProps) => {
+ const selectedOptionsWithCheckedState = selectOptions.map((option) => {
+ const isChecked = itemState.some(
+ (item) => item.name === option.value && item.method === option.method,
+ );
+ return { ...option, isChecked };
+ });
+
return (
-
-
-
-
-
-
-
-
-
-
- Distance
-
-
+ undefined}>
+
+
+
+ Apply
+
+ }
+ >
+
+
+
+
+
+
+
+
+
3km
10km
handleSliderChange(val)}
>
-
+
-
+
-
-
-
-
- Items
-
- item.name)}
- >
-
- {selectOptions.map((item) => (
- handleCheckboxChange(e)}
- key={item.idx}
- data-key={item.idx}
- value={item.value}
- name={item.method}
- >
- {item.value}
-
- ))}
-
-
-
-
+
+
+
+ );
+};
+
+function FilterSection({
+ title,
+ hideDivider,
+ button,
+ children,
+}: React.PropsWithChildren<{ title: string; hideDivider?: boolean; button?: JSX.Element }>) {
+ return (
+
+
+ {title}
+ {button}
+
+ {children}
+ {hideDivider ? (
+
+ ) : (
+
+ )}
+
+ );
+}
+
+const CheckboxGroup = ({
+ items,
+ onChange,
+ onSelectAll,
+}: {
+ items: Array<{
+ value: string;
+ method?: Methods;
+ isChecked: boolean;
+ }>;
+ onChange: (item: any) => void;
+ onSelectAll: () => void;
+}) => {
+ const { getCheckboxProps } = useCheckboxGroup({
+ value: items.filter((item) => item.isChecked).map((item) => item.value),
+ });
+
+ return (
+
+ {items.map((item) => (
+
+ ))}
+
+ Select All
+
+
+ );
+};
+
+const ChipCheckbox = (props: CheckboxProps) => {
+ const { state, getInputProps, htmlProps } = useCheckbox(props);
+
+ return (
+
+
+ {props.value}
+
+ );
+};
+
+const ChipRadioGroup = ({ items }: { items: Array }) => {
+ const { getRootProps, getRadioProps } = useRadioGroup({
+ name: "sortBy",
+ defaultValue: "Nearest",
+ });
+
+ const group = getRootProps();
+
+ return (
+
+ {items.map((value) => {
+ const radio = getRadioProps({ value });
+ return (
+
+ {value}
+
+ );
+ })}
+
+ );
+};
+
+const ChipRadio = (props: PropsWithChildren) => {
+ const { getInputProps, getRadioProps, state } = useRadio(props);
+
+ const input = getInputProps();
+
+ return (
+
+
+
+ {props.children}
+
);
};
+
+const Chip = ({
+ children,
+ isChecked,
+ darkBackground,
+}: React.PropsWithChildren<{ isChecked: boolean; darkBackground?: boolean }>) => {
+ const selectedColor = darkBackground ? "teal.500" : "teal.50";
+ const selectedTextColor = darkBackground ? "white" : "black";
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/client/components/map/HeaderButtons.tsx b/client/components/map/HeaderButtons.tsx
deleted file mode 100644
index 985d0c2..0000000
--- a/client/components/map/HeaderButtons.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Flex, Button, Spacer } from "@chakra-ui/react";
-import { COLORS } from "theme";
-import { Dispatch, SetStateAction } from "react";
-import { Pages } from "spa-pages/pageEnums";
-import { ArrowBackIcon, HamburgerIcon } from "@chakra-ui/icons";
-type Props = {
- setPage: Dispatch>;
-};
-
-export const HeaderButtons = ({ setPage }: Props) => {
- return (
- <>
-
-
- }
- onClick={() => setPage(Pages.HOME)}
- bg={COLORS["gray"][100]}
- color={COLORS.black}
- flex="1"
- py="3"
- >
- Edit
-
- }
- bg={COLORS.Button.primary}
- color={COLORS.white}
- flex="1"
- py="3"
- >
- View Results
-
-
- >
- );
-};
diff --git a/client/components/map/index.tsx b/client/components/map/index.tsx
index 29d86ee..17ad44b 100644
--- a/client/components/map/index.tsx
+++ b/client/components/map/index.tsx
@@ -1,6 +1,5 @@
export * from "./FacilityCard";
export * from "./FilterPanel";
-export * from "./HeaderButtons";
export * from "./MapContextProvider";
export * from "./NearbyFacilitiesPanel";
// export * from "./PullUpTab";
diff --git a/client/spa-pages/components/MapPage.tsx b/client/spa-pages/components/MapPage.tsx
index 270aad7..160e371 100644
--- a/client/spa-pages/components/MapPage.tsx
+++ b/client/spa-pages/components/MapPage.tsx
@@ -1,6 +1,6 @@
// General Imports
import { BasePage } from "layouts/BasePage";
-import { Flex, VStack, Box } from "@chakra-ui/react";
+import { Flex, VStack, Box, IconButton, useDisclosure } from "@chakra-ui/react";
import { Dispatch, SetStateAction, useState } from "react";
import { Pages } from "spa-pages/pageEnums";
import { useUserInputs } from "hooks/useUserSelection";
@@ -22,7 +22,7 @@ import GeneralIcon from "components/map/Marker/icons/GeneralIcon";
import ClusterIcon from "components/map/Marker/icons/ClusterIcon";
// import NearbyFacilitiesPanel from "components/map/NearbyFacilitiesPanel";
// import PullUpTab from "components/map/PullUpTab";
-import { HeaderButtons, FacilityCard, FilterPanel, MapContextProvider } from "components/map";
+import { FacilityCard, FilterPanel, MapContextProvider } from "components/map";
import { FilterButton } from "components/map/Buttons";
// Leaflet Imports
@@ -32,6 +32,7 @@ import useMapContext from "../../hooks/useMapContext";
import useLeafletWindow from "../../hooks/useLeafletWindow";
import { useResizeDetector } from "react-resize-detector";
import NonRecyclableModal from "components/common/NonRecyclableModal";
+import { ArrowBackIcon } from "@chakra-ui/icons";
// Reference page: https://github.com/richard-unterberg/next-leaflet-starter-typescript/blob/master/src/components/Map/ui/LocateButton.tsx
// Next.js requires dynamic imports for Leaflet.js compatibility
@@ -77,7 +78,7 @@ const MapInner = ({ setPage }: Props) => {
////// States //////
// Filters
- const [filterShow, setFilterShow] = useState(false);
+ const { isOpen: isFilterOpen, onOpen: onFilterOpen, onClose: onFilterClose } = useDisclosure();
const [range, setRange] = useState(60);
// const [isExpanded, setIsExpanded] = useState(false);
@@ -278,6 +279,23 @@ const MapInner = ({ setPage }: Props) => {
setItemState(updatedItemState);
};
+ const selectAllItems = () => {
+ const selectOptions: OptionType[] = items.map((item) => ({
+ value: item.name,
+ label: item.name,
+ method: item.method,
+ idx: index++,
+ }));
+ const itemState = items.map((item) => ({
+ name: item.name,
+ method: item.method,
+ }));
+
+ handleChangedLocation(itemState);
+ setItemState(itemState);
+ setSelectedOptions(selectOptions);
+ };
+
// Handle the changes in distance selected in Filter panel
const handleSliderChange = (val: number) => {
const dist = val / 10;
@@ -350,43 +368,15 @@ const MapInner = ({ setPage }: Props) => {
-
- {/* Header Buttons */}
-
-
- handleChangedLocation(itemState)}
- />
- {/* setFilterShow(false)} /> */}
- setFilterShow(true)} />
-
-
+
{facCardIsOpen &&
(isMobile ? (
@@ -425,18 +415,16 @@ const MapInner = ({ setPage }: Props) => {
getMatchingFacility={getMatchingFacility}
/>
)} */}
- {filterShow && (
- setFilterShow(true)}
- filterApply={() => setFilterShow(false)}
- handleSliderChange={handleSliderChange}
- range={range}
- itemState={itemState}
- selectOptions={selectOptions}
- handleCheckboxChange={handleCheckboxChange}
- />
- )}
+ onFilterClose()}
+ handleSliderChange={handleSliderChange}
+ range={range}
+ itemState={itemState}
+ selectOptions={selectOptions}
+ selectAllItems={selectAllItems}
+ handleCheckboxChange={handleCheckboxChange}
+ />
);
};
@@ -448,4 +436,139 @@ export const MapPage = ({ setPage }: Props) => (
);
+export const MapHeaderButtons = ({
+ setPage,
+ selectedOptions,
+ selectOptions,
+ handleMultiselectOnChange,
+ itemState,
+ handleChangedLocation,
+ onFilterOpen,
+}: {
+ setPage: Dispatch>;
+ selectedOptions: OptionType[];
+ selectOptions: OptionType[];
+ handleMultiselectOnChange: (
+ newValue: MultiValue,
+ actionMeta: ActionMeta,
+ ) => void;
+ itemState: (TItemSelection | TEmptyItem)[];
+ handleChangedLocation: (itemEntry: (TItemSelection | TEmptyItem)[]) => void;
+ onFilterOpen: () => void;
+}) => {
+ return (
+
+
+ }
+ onClick={() => setPage(Pages.HOME)}
+ bg="teal.600"
+ color="white"
+ aria-label="Back to home page"
+ boxShadow="2px 2px 8px 0px rgba(0, 0, 0, 0.50)"
+ />
+ handleChangedLocation(itemState)}
+ />
+
+
+
+
+
+
+ );
+};
+
+function SelectedItemChips({
+ selectedOptions,
+ handleMultiselectOnChange,
+ selectOptions,
+}: {
+ selectedOptions: OptionType[];
+ handleMultiselectOnChange: (
+ newValue: MultiValue,
+ actionMeta: ActionMeta,
+ ) => void;
+ selectOptions: OptionType[];
+}) {
+ return (
+