From f2be55e07b69afdc0b9fbafc3da9a29b68c285ca Mon Sep 17 00:00:00 2001
From: Himanshu Aggarwal <aggarwah@mcmaster.ca>
Date: Mon, 14 Mar 2022 00:02:13 -0400
Subject: [PATCH] Update components to support applying filters to
 cryptocurrencies

---
 .../components/dropdown/FilterDropdown.js     | 60 ++++++++++++-------
 .../components/radio/RadioForm.js             | 25 +++++---
 src/cryptometrics/pages/index.js              | 36 +++++++++--
 3 files changed, 87 insertions(+), 34 deletions(-)

diff --git a/src/cryptometrics/components/dropdown/FilterDropdown.js b/src/cryptometrics/components/dropdown/FilterDropdown.js
index 3781d9f..a95b636 100644
--- a/src/cryptometrics/components/dropdown/FilterDropdown.js
+++ b/src/cryptometrics/components/dropdown/FilterDropdown.js
@@ -13,11 +13,7 @@ export function FilterDropdown({ filterOptions, setOpen, addFilter }) {
 
   useEffect(() => {
     if (selectedFilter) {
-      setRadioValue(
-        filterOptions[selectedFilter].options[
-          Object.keys(filterOptions[selectedFilter].options)[0]
-        ].name
-      );
+      setRadioValue(Object.keys(filterOptions[selectedFilter].options)[0]);
     }
   }, [filterOptions, selectedFilter]);
 
@@ -35,7 +31,7 @@ export function FilterDropdown({ filterOptions, setOpen, addFilter }) {
 
   const onFilterAdd = () => {
     addFilter({
-      subject: filterOptions[selectedFilter].name,
+      subject: selectedFilter,
       condition: radioValue,
       value: inputValue,
     });
@@ -49,18 +45,22 @@ export function FilterDropdown({ filterOptions, setOpen, addFilter }) {
           "dark:bg-dark-600 w-56 h-max max-h-72 rounded-xl mt-2 transition-all duration-100 p-1 overflow-y-scroll shadow-lg shadow-dark-600"
         )}
       >
-        {Object.keys(filterOptions).map((key) => {
-          return (
-            <FilterDropdownItem
-              key={"primary_option_" + key}
-              selected={selectedFilter === key}
-              id={key}
-              onClick={onSelectedFilterChange}
-            >
-              {filterOptions[key].name}
-            </FilterDropdownItem>
-          );
-        })}
+        {Object.keys(filterOptions).length > 0 ? (
+          Object.keys(filterOptions).map((key) => {
+            return (
+              <FilterDropdownItem
+                key={"primary_option_" + key}
+                selected={selectedFilter === key}
+                id={key}
+                onClick={onSelectedFilterChange}
+              >
+                {filterOptions[key].name}
+              </FilterDropdownItem>
+            );
+          })
+        ) : (
+          <FilterDropdownItem disabled>No options available</FilterDropdownItem>
+        )}
       </div>
       <CSSTransition
         in={selectedFilter}
@@ -79,6 +79,9 @@ export function FilterDropdown({ filterOptions, setOpen, addFilter }) {
               inputValue={inputValue}
               onInputChange={onInputChange}
               onFilterAdd={onFilterAdd}
+              inputLeftSymbol={filterOptions[selectedFilter]?.symbol_left}
+              inputRightSymbol={filterOptions[selectedFilter]?.symbol_right}
+              inputType={filterOptions[selectedFilter]?.input_type}
             />
           </span>
         ) : (
@@ -98,6 +101,9 @@ export function SecondaryFilterDropdown({
   inputValue,
   onInputChange,
   onFilterAdd,
+  inputLeftSymbol,
+  inputRightSymbol,
+  inputType,
 }) {
   return (
     <div
@@ -115,6 +121,10 @@ export function SecondaryFilterDropdown({
         onRadioChange={onRadioChange}
         inputValue={inputValue}
         onInputChange={onInputChange}
+        inputLeftSymbol={inputLeftSymbol}
+        inputRightSymbol={inputRightSymbol}
+        inputType={inputType}
+        onSubmit={onFilterAdd}
       />
       <div className="flex flex-row space-x-2 mb-2">
         <Button
@@ -126,6 +136,7 @@ export function SecondaryFilterDropdown({
         <Button
           className="bg-indigo-600 text-white font-semibold w-full"
           onClick={onFilterAdd}
+          type="submit"
         >
           Filter
         </Button>
@@ -135,17 +146,24 @@ export function SecondaryFilterDropdown({
 }
 
 // selected: boolean
-function FilterDropdownItem({ children, selected, onClick, id }) {
+function FilterDropdownItem({
+  children,
+  selected,
+  onClick,
+  id,
+  disabled = false,
+}) {
   return (
     <div
       className={classNames(
-        "py-3 px-4 rounded-xl dark:text-neutral-100 hover:bg-dark-800 border-1 transition-all duration-100 cursor-pointer",
+        "py-3 px-4 rounded-xl dark:text-neutral-100 border-1 transition-all duration-100 cursor-pointer",
         {
           "border-transparent": !selected,
           "bg-dark-800  border-indigo-600 font-semibold": selected,
+          "hover:bg-dark-800": !disabled,
         }
       )}
-      onClick={() => onClick(id)}
+      onClick={disabled || !onClick ? undefined : () => onClick(id)}
     >
       <div className="flex flex-row items-center">
         {children}
diff --git a/src/cryptometrics/components/radio/RadioForm.js b/src/cryptometrics/components/radio/RadioForm.js
index 294d3db..79727e5 100644
--- a/src/cryptometrics/components/radio/RadioForm.js
+++ b/src/cryptometrics/components/radio/RadioForm.js
@@ -3,31 +3,38 @@ import React from "react";
 import Input from "../inputs/Input";
 
 export function RadioInputForm({
+  inputLeftSymbol,
+  inputRightSymbol,
+  inputType,
   options,
   radioValue,
   onRadioChange,
   inputValue,
   onInputChange,
+  onSubmit,
 }) {
   return (
-    <div>
+    <form onSubmit={onSubmit}>
       <div className="flex flex-col py-2 space-y-2">
         {Object.keys(options).map((key) => {
           return (
-            <div key={"radio_option_" + options[key].id}>
+            <div key={"radio_option_" + key}>
               <Radio
                 selected={radioValue}
-                radioValue={options[key].name}
-                id={options[key].id}
+                radioValue={key}
+                radioLabel={options[key].name}
+                id={key}
                 onChange={onRadioChange}
               />
               <div className="my-1">
-                {options[key].name === radioValue && (
+                {key === radioValue && (
                   <Input
-                    type="text"
                     placeholder="Enter a value here..."
                     initialValue={inputValue}
                     onChange={onInputChange}
+                    symbolLeft={inputLeftSymbol}
+                    symbolRight={inputRightSymbol}
+                    type={inputType}
                   />
                 )}
               </div>
@@ -35,11 +42,11 @@ export function RadioInputForm({
           );
         })}
       </div>
-    </div>
+    </form>
   );
 }
 
-export function Radio({ selected, radioValue, onChange }) {
+export function Radio({ selected, radioValue, radioLabel, onChange }) {
   return (
     <label className="inline-flex items-center w-full">
       <input
@@ -55,7 +62,7 @@ export function Radio({ selected, radioValue, onChange }) {
           "dark:text-indigo-500": selected === radioValue,
         })}
       >
-        {radioValue}
+        {radioLabel}
       </span>
     </label>
   );
diff --git a/src/cryptometrics/pages/index.js b/src/cryptometrics/pages/index.js
index ba9aa70..c018b2d 100644
--- a/src/cryptometrics/pages/index.js
+++ b/src/cryptometrics/pages/index.js
@@ -32,10 +32,23 @@ export default function Home() {
   const [dropdownOpen, setDropdownOpen] = useState(false);
   const [searchText, setSearchText] = useState("");
   const listOfCoins = useCryptoList("usd", 21, false);
-  const filteredCoins = listOfCoins.data?.filter((coin) => {
+
+  // Filter coins based on search
+  let filteredCoins = listOfCoins.data?.filter((coin) => {
     return coin.name.toLowerCase().includes(searchText.toLowerCase());
   });
 
+  // Apply filters
+  for (let i = 0; i < filters.length; i++) {
+    const { subject, condition, value } = filters[i];
+    filteredCoins = filteredCoins.filter((coin) => {
+      return filterOptions[subject]?.options[condition]?.function(
+        coin[subject],
+        value
+      );
+    });
+  }
+
   return (
     <div>
       <Head>
@@ -60,9 +73,14 @@ export default function Home() {
                   return (
                     <Filter
                       key={"filter_" + idx}
-                      subject={filter.subject}
-                      condition={filter.condition}
+                      subject={filterOptions[filter.subject]?.name}
+                      condition={
+                        filterOptions[filter.subject]?.options[filter.condition]
+                          ?.name
+                      }
                       value={filter.value}
+                      symbolLeft={filterOptions[filter.subject]?.symbol_left}
+                      symbolRight={filterOptions[filter.subject]?.symbol_right}
                       buttonIcon={<XIcon className="w-5 h-5" />}
                       onButtonClick={() => removeFilter(filter)}
                     />
@@ -80,7 +98,17 @@ export default function Home() {
                     <FilterDropdown
                       setOpen={setDropdownOpen}
                       addFilter={addFilter}
-                      filterOptions={filterOptions}
+                      filterOptions={Object.keys(filterOptions)
+                        .filter(
+                          (option) =>
+                            filters.filter(
+                              (filter) => filter.subject === option
+                            ).length === 0
+                        )
+                        .reduce((obj, key) => {
+                          obj[key] = filterOptions[key];
+                          return obj;
+                        }, {})}
                     />
                   )}
                 </div>
-- 
GitLab