Searchbar, state mngmt. etc.. #3
							
								
								
									
										54
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										54
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -15,11 +15,14 @@
 | 
				
			|||||||
        "@radix-ui/react-slot": "^1.0.2",
 | 
					        "@radix-ui/react-slot": "^1.0.2",
 | 
				
			||||||
        "@radix-ui/react-toast": "^1.1.5",
 | 
					        "@radix-ui/react-toast": "^1.1.5",
 | 
				
			||||||
        "@t3-oss/env-nextjs": "^0.10.1",
 | 
					        "@t3-oss/env-nextjs": "^0.10.1",
 | 
				
			||||||
 | 
					        "@types/react": "npm:types-react@rc",
 | 
				
			||||||
 | 
					        "@types/react-dom": "npm:types-react-dom@rc",
 | 
				
			||||||
        "@vercel/postgres": "^0.8.0",
 | 
					        "@vercel/postgres": "^0.8.0",
 | 
				
			||||||
        "class-variance-authority": "^0.7.0",
 | 
					        "class-variance-authority": "^0.7.0",
 | 
				
			||||||
        "clsx": "^2.1.1",
 | 
					        "clsx": "^2.1.1",
 | 
				
			||||||
        "drizzle-orm": "^0.29.4",
 | 
					        "drizzle-orm": "^0.29.4",
 | 
				
			||||||
        "geist": "^1.3.0",
 | 
					        "geist": "^1.3.0",
 | 
				
			||||||
 | 
					        "immer": "^10.1.1",
 | 
				
			||||||
        "lucide-react": "^0.379.0",
 | 
					        "lucide-react": "^0.379.0",
 | 
				
			||||||
        "next": "^15.0.0-rc.0",
 | 
					        "next": "^15.0.0-rc.0",
 | 
				
			||||||
        "postgres": "^3.4.3",
 | 
					        "postgres": "^3.4.3",
 | 
				
			||||||
@ -27,13 +30,14 @@
 | 
				
			|||||||
        "react-dom": "^19.0.0-rc-935180c7e0-20240524",
 | 
					        "react-dom": "^19.0.0-rc-935180c7e0-20240524",
 | 
				
			||||||
        "tailwind-merge": "^2.3.0",
 | 
					        "tailwind-merge": "^2.3.0",
 | 
				
			||||||
        "tailwindcss-animate": "^1.0.7",
 | 
					        "tailwindcss-animate": "^1.0.7",
 | 
				
			||||||
        "zod": "^3.23.8"
 | 
					        "zod": "^3.23.8",
 | 
				
			||||||
 | 
					        "zustand": "^4.5.2"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "@types/eslint": "^8.56.2",
 | 
					        "@types/eslint": "^8.56.2",
 | 
				
			||||||
        "@types/node": "^20.11.20",
 | 
					        "@types/node": "^20.11.20",
 | 
				
			||||||
        "@types/react": "^18.2.57",
 | 
					        "@types/react": "npm:types-react@rc",
 | 
				
			||||||
        "@types/react-dom": "^18.2.19",
 | 
					        "@types/react-dom": "npm:types-react-dom@rc",
 | 
				
			||||||
        "@typescript-eslint/eslint-plugin": "^7.1.1",
 | 
					        "@typescript-eslint/eslint-plugin": "^7.1.1",
 | 
				
			||||||
        "@typescript-eslint/parser": "^7.1.1",
 | 
					        "@typescript-eslint/parser": "^7.1.1",
 | 
				
			||||||
        "drizzle-kit": "^0.21.0",
 | 
					        "drizzle-kit": "^0.21.0",
 | 
				
			||||||
@ -5226,6 +5230,15 @@
 | 
				
			|||||||
        "node": ">= 4"
 | 
					        "node": ">= 4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/immer": {
 | 
				
			||||||
 | 
					      "version": "10.1.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "type": "opencollective",
 | 
				
			||||||
 | 
					        "url": "https://opencollective.com/immer"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/import-fresh": {
 | 
					    "node_modules/import-fresh": {
 | 
				
			||||||
      "version": "3.3.0",
 | 
					      "version": "3.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
 | 
				
			||||||
@ -8027,6 +8040,14 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/use-sync-external-store": {
 | 
				
			||||||
 | 
					      "version": "1.2.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/utf-8-validate": {
 | 
					    "node_modules/utf-8-validate": {
 | 
				
			||||||
      "version": "6.0.3",
 | 
					      "version": "6.0.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.3.tgz",
 | 
				
			||||||
@ -8313,6 +8334,33 @@
 | 
				
			|||||||
      "funding": {
 | 
					      "funding": {
 | 
				
			||||||
        "url": "https://github.com/sponsors/colinhacks"
 | 
					        "url": "https://github.com/sponsors/colinhacks"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/zustand": {
 | 
				
			||||||
 | 
					      "version": "4.5.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "use-sync-external-store": "1.2.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=12.7.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "@types/react": ">=16.8",
 | 
				
			||||||
 | 
					        "immer": ">=9.0.6",
 | 
				
			||||||
 | 
					        "react": ">=16.8"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "@types/react": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "immer": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "react": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								package.json
									
									
									
									
									
								
							@ -19,11 +19,14 @@
 | 
				
			|||||||
    "@radix-ui/react-slot": "^1.0.2",
 | 
					    "@radix-ui/react-slot": "^1.0.2",
 | 
				
			||||||
    "@radix-ui/react-toast": "^1.1.5",
 | 
					    "@radix-ui/react-toast": "^1.1.5",
 | 
				
			||||||
    "@t3-oss/env-nextjs": "^0.10.1",
 | 
					    "@t3-oss/env-nextjs": "^0.10.1",
 | 
				
			||||||
 | 
					    "@types/react": "npm:types-react@rc",
 | 
				
			||||||
 | 
					    "@types/react-dom": "npm:types-react-dom@rc",
 | 
				
			||||||
    "@vercel/postgres": "^0.8.0",
 | 
					    "@vercel/postgres": "^0.8.0",
 | 
				
			||||||
    "class-variance-authority": "^0.7.0",
 | 
					    "class-variance-authority": "^0.7.0",
 | 
				
			||||||
    "clsx": "^2.1.1",
 | 
					    "clsx": "^2.1.1",
 | 
				
			||||||
    "drizzle-orm": "^0.29.4",
 | 
					    "drizzle-orm": "^0.29.4",
 | 
				
			||||||
    "geist": "^1.3.0",
 | 
					    "geist": "^1.3.0",
 | 
				
			||||||
 | 
					    "immer": "^10.1.1",
 | 
				
			||||||
    "lucide-react": "^0.379.0",
 | 
					    "lucide-react": "^0.379.0",
 | 
				
			||||||
    "next": "^15.0.0-rc.0",
 | 
					    "next": "^15.0.0-rc.0",
 | 
				
			||||||
    "postgres": "^3.4.3",
 | 
					    "postgres": "^3.4.3",
 | 
				
			||||||
@ -31,13 +34,18 @@
 | 
				
			|||||||
    "react-dom": "^19.0.0-rc-935180c7e0-20240524",
 | 
					    "react-dom": "^19.0.0-rc-935180c7e0-20240524",
 | 
				
			||||||
    "tailwind-merge": "^2.3.0",
 | 
					    "tailwind-merge": "^2.3.0",
 | 
				
			||||||
    "tailwindcss-animate": "^1.0.7",
 | 
					    "tailwindcss-animate": "^1.0.7",
 | 
				
			||||||
    "zod": "^3.23.8"
 | 
					    "zod": "^3.23.8",
 | 
				
			||||||
 | 
					    "zustand": "^4.5.2"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "overrides": {
 | 
				
			||||||
 | 
					    "@types/react": "npm:types-react@rc",
 | 
				
			||||||
 | 
					    "@types/react-dom": "npm:types-react-dom@rc"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@types/eslint": "^8.56.2",
 | 
					    "@types/eslint": "^8.56.2",
 | 
				
			||||||
    "@types/node": "^20.11.20",
 | 
					    "@types/node": "^20.11.20",
 | 
				
			||||||
    "@types/react": "^18.2.57",
 | 
					    "@types/react": "npm:types-react@rc",
 | 
				
			||||||
    "@types/react-dom": "^18.2.19",
 | 
					    "@types/react-dom": "npm:types-react-dom@rc",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^7.1.1",
 | 
					    "@typescript-eslint/eslint-plugin": "^7.1.1",
 | 
				
			||||||
    "@typescript-eslint/parser": "^7.1.1",
 | 
					    "@typescript-eslint/parser": "^7.1.1",
 | 
				
			||||||
    "drizzle-kit": "^0.21.0",
 | 
					    "drizzle-kit": "^0.21.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,38 @@
 | 
				
			|||||||
 | 
					"use client";
 | 
				
			||||||
 | 
					import { Button } from "~/components/ui/button";
 | 
				
			||||||
import FormCard from "./_components/FormCard";
 | 
					import FormCard from "./_components/FormCard";
 | 
				
			||||||
 | 
					import useFilterStore from "./store";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AddRegionButton: React.FC = () => {
 | 
				
			||||||
 | 
					  const addRegion = useFilterStore((state) => state.addRegion);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleClick = () => {
 | 
				
			||||||
 | 
					    addRegion("sverige");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <Button onClick={handleClick}>Add Region "Sverige"</Button>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ResetFilters: React.FC = () => {
 | 
				
			||||||
 | 
					  const resetFilters = useFilterStore((state) => state.resetFilters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleClick = () => {
 | 
				
			||||||
 | 
					    resetFilters();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <Button onClick={handleClick}>Reset filters</Button>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function App() {
 | 
					export default function App() {
 | 
				
			||||||
 | 
					  const filters = useFilterStore((state) => state.filters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="container flex w-full flex-col justify-center">
 | 
					    <div className="container flex w-full flex-col justify-center">
 | 
				
			||||||
      <FormCard />
 | 
					      <FormCard />
 | 
				
			||||||
 | 
					      <h1 className="text-2xl">Filter state:</h1>
 | 
				
			||||||
 | 
					      {JSON.stringify(filters)}
 | 
				
			||||||
 | 
					      <AddRegionButton />
 | 
				
			||||||
 | 
					      <ResetFilters />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,28 +10,33 @@ import {
 | 
				
			|||||||
import { Input } from "~/components/ui/input";
 | 
					import { Input } from "~/components/ui/input";
 | 
				
			||||||
import { Slider } from "~/components/ui/slider";
 | 
					import { Slider } from "~/components/ui/slider";
 | 
				
			||||||
import { ChangeEvent, useState } from "react";
 | 
					import { ChangeEvent, useState } from "react";
 | 
				
			||||||
 | 
					import useFilterStore from "../store";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Filtermenu() {
 | 
					export default function Filtermenu() {
 | 
				
			||||||
  const [minPrice, setMinPrice] = useState<number>(0);
 | 
					  const [minPrice, setMinPrice] = useState<number>(0);
 | 
				
			||||||
  const [maxPrice, setMaxPrice] = useState<number>(9999);
 | 
					  const [maxPrice, setMaxPrice] = useState<number>(9999);
 | 
				
			||||||
  const [sliderValues, setSliderValues] = useState<[number, number]>([0, 9999]);
 | 
					  const [sliderValues, setSliderValues] = useState<[number, number]>([0, 9999]);
 | 
				
			||||||
 | 
					  const setStorePrice = useFilterStore((state) => state.setPrice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleMinPriceChange = (e: ChangeEvent<HTMLInputElement>): void => {
 | 
					  const handleMinPriceChange = (e: ChangeEvent<HTMLInputElement>): void => {
 | 
				
			||||||
    const value = Math.min(Number(e.target.value), maxPrice - 1);
 | 
					    const value = Math.min(Number(e.target.value), maxPrice - 1);
 | 
				
			||||||
    setMinPrice(value);
 | 
					    setMinPrice(value);
 | 
				
			||||||
    setSliderValues([value, sliderValues[1]]);
 | 
					    setSliderValues([value, sliderValues[1]]);
 | 
				
			||||||
 | 
					    setStorePrice(minPrice, maxPrice);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleMaxPriceChange = (e: ChangeEvent<HTMLInputElement>) => {
 | 
					  const handleMaxPriceChange = (e: ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
    const value = Math.max(Number(e.target.value), minPrice + 1);
 | 
					    const value = Math.max(Number(e.target.value), minPrice + 1);
 | 
				
			||||||
    setMaxPrice(value);
 | 
					    setMaxPrice(value);
 | 
				
			||||||
    setSliderValues([sliderValues[0], value]);
 | 
					    setSliderValues([sliderValues[0], value]);
 | 
				
			||||||
 | 
					    setStorePrice(minPrice, maxPrice);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleSliderChange = (values: [number, number]) => {
 | 
					  const handleSliderChange = (values: [number, number]) => {
 | 
				
			||||||
    setSliderValues(values);
 | 
					    setSliderValues(values);
 | 
				
			||||||
    setMinPrice(values[0]);
 | 
					    setMinPrice(values[0]);
 | 
				
			||||||
    setMaxPrice(values[1]);
 | 
					    setMaxPrice(values[1]);
 | 
				
			||||||
 | 
					    setStorePrice(minPrice, maxPrice);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								src/app/_components/SearchBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/app/_components/SearchBar.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import { Input } from "~/components/ui/input";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function SearchBar() {
 | 
				
			||||||
 | 
					  return <Input className="mx-auto max-w-xl focus-visible:ring-0" />;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,3 +0,0 @@
 | 
				
			|||||||
export default function WineName(props: { name: string }) {
 | 
					 | 
				
			||||||
  return <p>{props.name}</p>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,25 +0,0 @@
 | 
				
			|||||||
import getProducer from "~/server/actions/getProducer";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default async function WineProducer(props: { id: string }) {
 | 
					 | 
				
			||||||
  const { id } = props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Validate the id before making the database call
 | 
					 | 
				
			||||||
  if (!id) {
 | 
					 | 
				
			||||||
    return <p>Invalid producer ID</p>;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    const result = await getProducer(id);
 | 
					 | 
				
			||||||
    return !result ? <p>Unable to retrieve producer</p> : <p>{result?.name}</p>;
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    console.error("Error fetching producer:", error);
 | 
					 | 
				
			||||||
    return <p>Error fetching producer</p>;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Utility function to validate UUID
 | 
					 | 
				
			||||||
function isValidUUID(uuid: string) {
 | 
					 | 
				
			||||||
  const uuidRegex =
 | 
					 | 
				
			||||||
    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
 | 
					 | 
				
			||||||
  return uuidRegex.test(uuid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -4,6 +4,7 @@ import { Inter as FontSans } from "next/font/google";
 | 
				
			|||||||
import { cn } from "~/lib/utils";
 | 
					import { cn } from "~/lib/utils";
 | 
				
			||||||
import TopNav from "./_components/FilterMenu";
 | 
					import TopNav from "./_components/FilterMenu";
 | 
				
			||||||
import Filtermenu from "./_components/FilterMenu";
 | 
					import Filtermenu from "./_components/FilterMenu";
 | 
				
			||||||
 | 
					import SearchBar from "./_components/SearchBar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fontSans = FontSans({
 | 
					const fontSans = FontSans({
 | 
				
			||||||
  subsets: ["latin"],
 | 
					  subsets: ["latin"],
 | 
				
			||||||
@ -29,7 +30,10 @@ export default function RootLayout({
 | 
				
			|||||||
          fontSans.variable,
 | 
					          fontSans.variable,
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <Filtermenu />
 | 
					        <div className="container pt-12">
 | 
				
			||||||
 | 
					          <SearchBar />
 | 
				
			||||||
 | 
					          <Filtermenu />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
        {children}
 | 
					        {children}
 | 
				
			||||||
      </body>
 | 
					      </body>
 | 
				
			||||||
    </html>
 | 
					    </html>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										156
									
								
								src/app/store.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								src/app/store.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					import { create } from "zustand";
 | 
				
			||||||
 | 
					import { produce } from "immer";
 | 
				
			||||||
 | 
					import { persist, createJSONStorage } from "zustand/middleware";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface FilterState {
 | 
				
			||||||
 | 
					  filters: Filters;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Filters {
 | 
				
			||||||
 | 
					  searchQuery: string;
 | 
				
			||||||
 | 
					  regions: string[];
 | 
				
			||||||
 | 
					  countries: string[];
 | 
				
			||||||
 | 
					  producers: string[];
 | 
				
			||||||
 | 
					  price: Price;
 | 
				
			||||||
 | 
					  type: WineType;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Price {
 | 
				
			||||||
 | 
					  min: number;
 | 
				
			||||||
 | 
					  max: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface WineType {
 | 
				
			||||||
 | 
					  sparkling: boolean;
 | 
				
			||||||
 | 
					  white: boolean;
 | 
				
			||||||
 | 
					  red: boolean;
 | 
				
			||||||
 | 
					  sweet: boolean;
 | 
				
			||||||
 | 
					  other: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type FilterActions = {
 | 
				
			||||||
 | 
					  addRegion: (region: string) => void;
 | 
				
			||||||
 | 
					  removeRegion: (region: string) => void;
 | 
				
			||||||
 | 
					  addCountry: (country: string) => void;
 | 
				
			||||||
 | 
					  removeCountry: (country: string) => void;
 | 
				
			||||||
 | 
					  addProducer: (producer: string) => void;
 | 
				
			||||||
 | 
					  removeProducer: (producer: string) => void;
 | 
				
			||||||
 | 
					  setPrice: (min: number, max: number) => void;
 | 
				
			||||||
 | 
					  setType: (type: keyof WineType, value: boolean) => void;
 | 
				
			||||||
 | 
					  resetFilters: () => void;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initialFilters: Filters = {
 | 
				
			||||||
 | 
					  searchQuery: "",
 | 
				
			||||||
 | 
					  regions: [],
 | 
				
			||||||
 | 
					  countries: [],
 | 
				
			||||||
 | 
					  producers: [],
 | 
				
			||||||
 | 
					  price: {
 | 
				
			||||||
 | 
					    min: 0,
 | 
				
			||||||
 | 
					    max: 9999,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  type: {
 | 
				
			||||||
 | 
					    sparkling: false,
 | 
				
			||||||
 | 
					    white: false,
 | 
				
			||||||
 | 
					    red: false,
 | 
				
			||||||
 | 
					    sweet: false,
 | 
				
			||||||
 | 
					    other: false,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useFilterStore = create<FilterState & FilterActions>()(
 | 
				
			||||||
 | 
					  persist(
 | 
				
			||||||
 | 
					    (set) => ({
 | 
				
			||||||
 | 
					      filters: {
 | 
				
			||||||
 | 
					        searchQuery: "",
 | 
				
			||||||
 | 
					        regions: [],
 | 
				
			||||||
 | 
					        countries: [],
 | 
				
			||||||
 | 
					        producers: [],
 | 
				
			||||||
 | 
					        price: {
 | 
				
			||||||
 | 
					          min: 0,
 | 
				
			||||||
 | 
					          max: 9999,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        type: {
 | 
				
			||||||
 | 
					          sparkling: false,
 | 
				
			||||||
 | 
					          white: false,
 | 
				
			||||||
 | 
					          red: false,
 | 
				
			||||||
 | 
					          sweet: false,
 | 
				
			||||||
 | 
					          other: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      addRegion: (region) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            if (!state.filters.regions.includes(region)) {
 | 
				
			||||||
 | 
					              state.filters.regions.push(region);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      removeRegion: (region) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            state.filters.regions = state.filters.regions.filter(
 | 
				
			||||||
 | 
					              (r) => r !== region,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      addCountry: (country) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            if (!state.filters.countries.includes(country)) {
 | 
				
			||||||
 | 
					              state.filters.countries.push(country);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      removeCountry: (country) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            state.filters.countries = state.filters.countries.filter(
 | 
				
			||||||
 | 
					              (c) => c !== country,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      addProducer: (producer) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            if (!state.filters.producers.includes(producer)) {
 | 
				
			||||||
 | 
					              state.filters.producers.push(producer);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      removeProducer: (producer) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            state.filters.producers = state.filters.producers.filter(
 | 
				
			||||||
 | 
					              (p) => p !== producer,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      setPrice: (min, max) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            state.filters.price.min = min;
 | 
				
			||||||
 | 
					            state.filters.price.max = max;
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      setType: (type, value) =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            state.filters.type[type] = value;
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      resetFilters: () =>
 | 
				
			||||||
 | 
					        set(
 | 
				
			||||||
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
 | 
					            state.filters = initialFilters;
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: "filter-storage", // name of the item in the storage (must be unique)
 | 
				
			||||||
 | 
					      storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useFilterStore;
 | 
				
			||||||
@ -1,8 +0,0 @@
 | 
				
			|||||||
export interface Producer {
 | 
					 | 
				
			||||||
    id: string;
 | 
					 | 
				
			||||||
    name: string;
 | 
					 | 
				
			||||||
    createdAt: Date;
 | 
					 | 
				
			||||||
    country: string;
 | 
					 | 
				
			||||||
    region: string;
 | 
					 | 
				
			||||||
    email: string;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user