diff --git a/src/app/layout.tsx b/src/app/layout.tsx index da515e1..3372c1a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,6 +5,8 @@ import Header from "@/components/ui/header"; import { AuthProvider } from "@/providers/auth"; import Footer from "@/components/ui/footer"; import CartProvider from "@/providers/cart"; +import Search from "@/components/ui/search"; +import SearchProvider from "@/providers/search"; const inter = Inter({ subsets: ["latin"] }); @@ -23,11 +25,14 @@ export default function RootLayout({
+
+
{children}
diff --git a/src/app/product/[slug]/components/product-info.tsx b/src/app/product/[slug]/components/product-info.tsx index 79af74b..76626ee 100644 --- a/src/app/product/[slug]/components/product-info.tsx +++ b/src/app/product/[slug]/components/product-info.tsx @@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button"; import DiscountBadge from "@/components/ui/discount-badge"; +import { convertCurrencyToReal } from "@/helpers/convert-currency"; import { ProductWithTotalPrice } from "@/helpers/product"; import { CartContext } from "@/providers/cart"; import { ArrowLeftIcon, ArrowRightIcon, TruckIcon } from "lucide-react"; @@ -34,7 +35,7 @@ const ProductInfo = ({ product }: ProductInfoProps) => {

- R$ {product.totalPrice.toFixed(2)} + {convertCurrencyToReal(product.totalPrice)}

{product.discountPercentage > 0 && ( @@ -45,7 +46,7 @@ const ProductInfo = ({ product }: ProductInfoProps) => { {product.discountPercentage > 0 && (

- R$ {Number(product.basePrice).toFixed(2)} + {convertCurrencyToReal(Number(product.basePrice))}

)} diff --git a/src/components/ui/cart-item.tsx b/src/components/ui/cart-item.tsx index 6a61ed7..72278eb 100644 --- a/src/components/ui/cart-item.tsx +++ b/src/components/ui/cart-item.tsx @@ -3,6 +3,7 @@ import Image from "next/image"; import { Button } from "./button"; import { ArrowLeftIcon, ArrowRightIcon, TrashIcon } from "lucide-react"; import { useContext } from "react"; +import { convertCurrencyToReal } from "@/helpers/convert-currency"; interface CartItemProps { product: CartProduct; @@ -48,11 +49,11 @@ const CartItem = ({ product }: CartItemProps) => {

- R$ {product.totalPrice.toFixed(2)} + {convertCurrencyToReal(product.totalPrice)}

{product.discountPercentage > 0 && (

- R$ {Number(product.basePrice).toFixed(2)} + {convertCurrencyToReal(Number(product.basePrice))}

)}
diff --git a/src/components/ui/product-item.tsx b/src/components/ui/product-item.tsx index 4c53820..7ab9bc2 100644 --- a/src/components/ui/product-item.tsx +++ b/src/components/ui/product-item.tsx @@ -3,6 +3,7 @@ import Image from "next/image"; import Link from "next/link"; import DiscountBadge from "./discount-badge"; import { cn } from "@/lib/utils"; +import { convertCurrencyToReal } from "@/helpers/convert-currency"; interface ProductItemProps { product: ProductWithTotalPrice; @@ -39,16 +40,16 @@ const ProductItem = ({ product, className }: ProductItemProps) => { {product.discountPercentage > 0 ? ( <>

- R$ {product.totalPrice.toFixed(2)} + {convertCurrencyToReal(product.totalPrice)}

- R$ {Number(product.basePrice).toFixed(2)} + {convertCurrencyToReal(Number(product.basePrice))}

) : (

- R$ {product.basePrice.toFixed(2)} + {convertCurrencyToReal(Number(product.basePrice))}

)}
diff --git a/src/components/ui/search-bar.tsx b/src/components/ui/search-bar.tsx new file mode 100644 index 0000000..5afd53d --- /dev/null +++ b/src/components/ui/search-bar.tsx @@ -0,0 +1,28 @@ +'use client' +import useSearch from '@/hooks/use-search' +import { SearchIcon } from 'lucide-react' +import React, { ReactNode } from 'react' + +const SearchBar = ({children}: {children: ReactNode}) => { + const { search, onChange } = useSearch() + + return ( +
+
+ + +
+ {children} +
+ ) +} + +export default SearchBar \ No newline at end of file diff --git a/src/components/ui/search-card-result.tsx b/src/components/ui/search-card-result.tsx new file mode 100644 index 0000000..933868a --- /dev/null +++ b/src/components/ui/search-card-result.tsx @@ -0,0 +1,41 @@ +'use client' +import { ProductWithTotalPrice } from '@/helpers/product' +import React from 'react' +import Image from 'next/image' +import { convertCurrencyToReal } from '@/helpers/convert-currency' +import Link from 'next/link' +import useSearch from '@/hooks/use-search' + +const SearchCardResult = ({ product }: {product: ProductWithTotalPrice | undefined}) => { + const { setSearch } = useSearch() + + if (!product) { + return null + } + + return ( + setSearch('')} + key={product.id} + className='flex gap-4'> +
+ {product.description} +
+
+

{product.name}

+ {convertCurrencyToReal(product.totalPrice)} + {convertCurrencyToReal(Number(product.basePrice))} +
+ + ) +} + +export default SearchCardResult \ No newline at end of file diff --git a/src/components/ui/search-results.tsx b/src/components/ui/search-results.tsx new file mode 100644 index 0000000..c408fb0 --- /dev/null +++ b/src/components/ui/search-results.tsx @@ -0,0 +1,43 @@ +'use client' +import React from 'react' +import { computeProductTotalPrice } from '@/helpers/product' +import SearchCardResult from './search-card-result' +import { Product } from '@prisma/client' +import useSearch from '@/hooks/use-search' + +interface SearchResultsProps { + products: Product[] +} + +const SearchResults = ({ products }: SearchResultsProps ) => { + const { deferredSearch } = useSearch(); + const [filteredProducts, setFilteredProducts] = React.useState([]) + + + React.useEffect(() => { + const filtered = products.filter((product) => product.name.toLowerCase().includes(deferredSearch.toLowerCase()) ) + setFilteredProducts(filtered) + }, [deferredSearch, products]) + + if (!deferredSearch) return null + + return ( + + ) +} + +export default SearchResults \ No newline at end of file diff --git a/src/components/ui/search.tsx b/src/components/ui/search.tsx new file mode 100644 index 0000000..f2940f5 --- /dev/null +++ b/src/components/ui/search.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import SearchBar from './search-bar' +import SearchResults from './search-results' +import { prismaClient } from "@/lib/prisma"; + +const Search = async () => { + const products = await prismaClient.product.findMany({}) + console.log(products) + return ( +
+ + + +
+ ) +} + +export default Search \ No newline at end of file diff --git a/src/helpers/convert-currency.ts b/src/helpers/convert-currency.ts new file mode 100644 index 0000000..0a4d528 --- /dev/null +++ b/src/helpers/convert-currency.ts @@ -0,0 +1,8 @@ +export const convertCurrencyToReal = (value: number) => { + return value.toLocaleString( + 'pt-BR', { + style: 'currency', + currency: 'BRL' + } + ) +} \ No newline at end of file diff --git a/src/hooks/use-search.tsx b/src/hooks/use-search.tsx new file mode 100644 index 0000000..6792002 --- /dev/null +++ b/src/hooks/use-search.tsx @@ -0,0 +1,8 @@ +import React from "react" +import { ISearch } from "@/providers/search" + +const useSearch = () => { + return React.useContext(ISearch) +} + +export default useSearch \ No newline at end of file diff --git a/src/providers/search.tsx b/src/providers/search.tsx new file mode 100644 index 0000000..d901ffa --- /dev/null +++ b/src/providers/search.tsx @@ -0,0 +1,29 @@ +'use client' +import React, { ReactNode, SetStateAction } from 'react' + +interface ISearchProps { + search: string | undefined + onChange: (e: React.ChangeEvent) => void + deferredSearch: string + setSearch: React.Dispatch> +} + +export const ISearch = React.createContext({} as ISearchProps) + +const SearchProvider = ({ children }: { children: ReactNode }) => { + const [search, setSearch] = React.useState('') + const deferredSearch = React.useDeferredValue(search) + + const onChange = React.useCallback((e: React.ChangeEvent) => { + setSearch(e.target.value) + }, []) + + return ( + + {children} + + ) +} + +export default SearchProvider +