React Hooks

Hooks

Built-in React Hooks

useState

Home

const [isShowValues, setIsShowValues] = useState(true);
 
const toggleShowValues = () => {
  setIsShowValues(!isShowValues);
};
const [isShowValues, setIsShowValues] = useState(true);
 
const toggleShowValues = () => {
  setIsShowValues(!isShowValues);
};

Conditional Rendering

{isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
{isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import { useState } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
import { investments } from '@/data/seed';
 
export default function Home() {
  const [isShowValues, setIsShowValues] = useState(true);
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  return (
    <>
      <header className="my-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard
            {...investment}
            isShowValue={isShowValues}
            key={investment.id}
          />
        ))}
      </div>
    </>
  );
}
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import { useState } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
import { investments } from '@/data/seed';
 
export default function Home() {
  const [isShowValues, setIsShowValues] = useState(true);
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  return (
    <>
      <header className="my-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard
            {...investment}
            isShowValue={isShowValues}
            key={investment.id}
          />
        ))}
      </div>
    </>
  );
}

InvestmentCard

{isShowValue ? formatCurrency(value / 100) : 'R$ ****'}
{isShowValue ? formatCurrency(value / 100) : 'R$ ****'}
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
'use client';
 
import Link from 'next/link';
 
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
  isShowValue,
}) {
  const handleDeleteInvestment = (name) => {
    confirm(`Deseja remover ${name}?`);
  };
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValue ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        ...
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleDeleteInvestment(name)}
        />
      </div>
    </div>
  );
}
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
'use client';
 
import Link from 'next/link';
 
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
  isShowValue,
}) {
  const handleDeleteInvestment = (name) => {
    confirm(`Deseja remover ${name}?`);
  };
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValue ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        ...
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleDeleteInvestment(name)}
        />
      </div>
    </div>
  );
}

useEffect

Home

const loadInvestment = async () => {
  const investments = await Storage.read('investments');
 
  setInvestments(investments);
};
 
useEffect(() => {
  loadInvestment();
}, []);
const loadInvestment = async () => {
  const investments = await Storage.read('investments');
 
  setInvestments(investments);
};
 
useEffect(() => {
  loadInvestment();
}, []);
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import Storage from '@/services/supabase';
import { useEffect, useState } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
 
export default function Home() {
  const [isShowValues, setIsShowValues] = useState(true);
  const [investments, setInvestments] = useState([]);
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  const loadInvestment = async () => {
    const investments = await Storage.read('investments');
 
    setInvestments(investments);
  };
 
  useEffect(() => {
    loadInvestment();
  }, []);
 
  return (
    <>
      <header className="my-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard
            {...investment}
            isShowValue={isShowValues}
            investments={investments}
            setInvestments={setInvestments}
            key={investment.id}
          />
        ))}
      </div>
    </>
  );
}
 
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import Storage from '@/services/supabase';
import { useEffect, useState } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
 
export default function Home() {
  const [isShowValues, setIsShowValues] = useState(true);
  const [investments, setInvestments] = useState([]);
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  const loadInvestment = async () => {
    const investments = await Storage.read('investments');
 
    setInvestments(investments);
  };
 
  useEffect(() => {
    loadInvestment();
  }, []);
 
  return (
    <>
      <header className="my-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard
            {...investment}
            isShowValue={isShowValues}
            investments={investments}
            setInvestments={setInvestments}
            key={investment.id}
          />
        ))}
      </div>
    </>
  );
}
 

InvestmentCard

const handleDeleteInvestment = (id) => {
  if (confirm(`Deseja remover ${name}?`)) {
    const newInvestments = investments.filter(
      (investment) => investment.id !== id
    );
 
    setInvestments(newInvestments);
 
    Storage.remove('investments', id);
  }
};
const handleDeleteInvestment = (id) => {
  if (confirm(`Deseja remover ${name}?`)) {
    const newInvestments = investments.filter(
      (investment) => investment.id !== id
    );
 
    setInvestments(newInvestments);
 
    Storage.remove('investments', id);
  }
};
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
  isShowValue,
  investments,
  setInvestments,
}) {
  const handleDeleteInvestment = (id) => {
    if (confirm(`Deseja remover ${name}?`)) {
      const newInvestments = investments.filter(
        (investment) => investment.id !== id
      );
 
      setInvestments(newInvestments);
 
      Storage.remove('investments', id);
    }
  };
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValue ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        ...
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleDeleteInvestment(id)}
        />
      </div>
    </div>
  );
}
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
  isShowValue,
  investments,
  setInvestments,
}) {
  const handleDeleteInvestment = (id) => {
    if (confirm(`Deseja remover ${name}?`)) {
      const newInvestments = investments.filter(
        (investment) => investment.id !== id
      );
 
      setInvestments(newInvestments);
 
      Storage.remove('investments', id);
    }
  };
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValue ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        ...
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleDeleteInvestment(id)}
        />
      </div>
    </div>
  );
}

useContext

InvestmentContext

/codes/react/hooks/invest-app/src/context/InvestmentContext.jsx
'use client';
 
import { createContext, useState, useContext } from 'react';
 
export const InvestmentContext = createContext({});
 
export function InvestmentProvider({ children }) {
  const [investments, setInvestments] = useState([]);
 
  ...
 
  return (
    <InvestmentContext.Provider
      value={{
        investments,
        setInvestments,
        ...
      }}
    >
      {children}
    </InvestmentContext.Provider>
  );
}
 
export function useInvestment() {
  return useContext(InvestmentContext);
}
/codes/react/hooks/invest-app/src/context/InvestmentContext.jsx
'use client';
 
import { createContext, useState, useContext } from 'react';
 
export const InvestmentContext = createContext({});
 
export function InvestmentProvider({ children }) {
  const [investments, setInvestments] = useState([]);
 
  ...
 
  return (
    <InvestmentContext.Provider
      value={{
        investments,
        setInvestments,
        ...
      }}
    >
      {children}
    </InvestmentContext.Provider>
  );
}
 
export function useInvestment() {
  return useContext(InvestmentContext);
}
/codes/react/hooks/invest-app/src/context/InvestmentContext.jsx
'use client';
 
import { createContext, useState, useContext } from 'react';
import Storage from '@/services/supabase';
 
export const InvestmentContext = createContext({});
 
export function InvestmentProvider({ children }) {
  const [investments, setInvestments] = useState([]);
 
  const [isShowValues, setIsShowValues] = useState(true);
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  const loadInvestments = async () => {
    const investments = await Storage.read('investments');
 
    setInvestments(investments);
  };
 
  const removeInvestment = (id) => {
    const newInvestments = investments.filter(
      (investment) => investment.id !== id
    );
 
    setInvestments(newInvestments);
 
    Storage.remove('investments', id);
  };
 
  return (
    <InvestmentContext.Provider
      value={{
        investments,
        setInvestments,
        isShowValues,
        setIsShowValues,
        toggleShowValues,
        loadInvestments,
        removeInvestment,
      }}
    >
      {children}
    </InvestmentContext.Provider>
  );
}
 
export function useInvestment() {
  return useContext(InvestmentContext);
}
/codes/react/hooks/invest-app/src/context/InvestmentContext.jsx
'use client';
 
import { createContext, useState, useContext } from 'react';
import Storage from '@/services/supabase';
 
export const InvestmentContext = createContext({});
 
export function InvestmentProvider({ children }) {
  const [investments, setInvestments] = useState([]);
 
  const [isShowValues, setIsShowValues] = useState(true);
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  const loadInvestments = async () => {
    const investments = await Storage.read('investments');
 
    setInvestments(investments);
  };
 
  const removeInvestment = (id) => {
    const newInvestments = investments.filter(
      (investment) => investment.id !== id
    );
 
    setInvestments(newInvestments);
 
    Storage.remove('investments', id);
  };
 
  return (
    <InvestmentContext.Provider
      value={{
        investments,
        setInvestments,
        isShowValues,
        setIsShowValues,
        toggleShowValues,
        loadInvestments,
        removeInvestment,
      }}
    >
      {children}
    </InvestmentContext.Provider>
  );
}
 
export function useInvestment() {
  return useContext(InvestmentContext);
}

RootLayout

/codes/react/hooks/invest-app/src/app/layout.jsx
import { Inter } from 'next/font/google';
import { InvestmentProvider } from '@/contexts/InvestmentContext';
 
import './globals.css';
 
const inter = Inter({ subsets: ['latin'] });
 
export const metadata = {
  title: 'invest-app',
  description: 'Aplicação de investimentos',
};
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={`${inter.className} bg-gray-100`}>
        <div className="container min-h-screen mx-auto lg:max-w-screen-lg">
          <InvestmentProvider>{children}</InvestmentProvider>
        </div>
      </body>
    </html>
  );
}
/codes/react/hooks/invest-app/src/app/layout.jsx
import { Inter } from 'next/font/google';
import { InvestmentProvider } from '@/contexts/InvestmentContext';
 
import './globals.css';
 
const inter = Inter({ subsets: ['latin'] });
 
export const metadata = {
  title: 'invest-app',
  description: 'Aplicação de investimentos',
};
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={`${inter.className} bg-gray-100`}>
        <div className="container min-h-screen mx-auto lg:max-w-screen-lg">
          <InvestmentProvider>{children}</InvestmentProvider>
        </div>
      </body>
    </html>
  );
}

Home

const { investments, loadInvestments, isShowValues, toggleShowValues } =
    useInvestment();
const { investments, loadInvestments, isShowValues, toggleShowValues } =
    useInvestment();
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import { useEffect } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function Home() {
  const { investments, loadInvestments, isShowValues, toggleShowValues } =
    useInvestment();
 
  useEffect(() => {
    loadInvestments();
  }, []);
 
  return (
    <>
      <header className="my-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard {...investment} key={investment.id} />
        ))}
      </div>
    </>
  );
}
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import { useEffect } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function Home() {
  const { investments, loadInvestments, isShowValues, toggleShowValues } =
    useInvestment();
 
  useEffect(() => {
    loadInvestments();
  }, []);
 
  return (
    <>
      <header className="my-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard {...investment} key={investment.id} />
        ))}
      </div>
    </>
  );
}

InvestmentCard

const { removeInvestment, isShowValues } = useInvestment();
const { removeInvestment, isShowValues } = useInvestment();
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
'use client';
 
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
}) {
  const { removeInvestment, isShowValues } = useInvestment();
 
  const handleDeleteInvestment = (id) => {
    if (confirm(`Deseja remover ${name}?`)) {
      removeInvestment(id);
    }
  };
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValues ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        ...
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleDeleteInvestment(id)}
        />
      </div>
    </div>
  );
}
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
'use client';
 
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
}) {
  const { removeInvestment, isShowValues } = useInvestment();
 
  const handleDeleteInvestment = (id) => {
    if (confirm(`Deseja remover ${name}?`)) {
      removeInvestment(id);
    }
  };
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValues ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        ...
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleDeleteInvestment(id)}
        />
      </div>
    </div>
  );
}

Invest-app (CRUD)

Código Fonte

InvestmenContext

/codes/react/hooks/invest-app/src/context/InvestmenContext.jsx
'use client';
 
import { createContext, useState, useContext } from 'react';
import Storage from '@/services/supabase';
import { formatDate } from '@/lib/format';
 
export const InvestmentContext = createContext({});
 
export function InvestmentProvider({ children }) {
  const initialInvestmentFormData = {
    name: '',
    value: '',
    origin: '',
    category: '',
    interest: '',
    created_at: '',
  };
 
  const [investments, setInvestments] = useState([]);
 
  const [isShowValues, setIsShowValues] = useState(true);
 
  const [isShowModal, setIsShowModal] = useState(false);
 
  const [isShowInvestmentForm, setIsShowInvestmentForm] = useState(false);
 
  const [investmentModalData, setInvestmentModalData] = useState({});
 
  const [investmentFormData, setInvestmentFormData] = useState(
    initialInvestmentFormData
  );
 
  const [investmentFormAction, setInvestmentFormAction] = useState('');
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  const toggleShowModal = () => {
    setIsShowModal(!isShowModal);
  };
 
  const toggleShowInvestmentForm = () => {
    setIsShowInvestmentForm(!isShowInvestmentForm);
  };
 
  const loadInvestments = async () => {
    const investments = await Storage.read('investments');
 
    setInvestments(investments);
  };
 
  const createInvestment = async (investment) => {
    const newInvestment = await Storage.create('investments', investment);
 
    setInvestments([...investments, newInvestment]);
  };
 
  const updateInvestment = async (investment) => {
    const newInvestments = investments.filter(
      (item) => item.id !== investment.id
    );
 
    setInvestments([...newInvestments, investment]);
 
    Storage.update('investments', investment);
  };
 
  const removeInvestment = (id) => {
    const newInvestments = investments.filter(
      (investment) => investment.id !== id
    );
 
    setInvestments(newInvestments);
 
    Storage.remove('investments', id);
  };
 
  const handleLoadModalData = (id) => {
    const investment = investments.find((investment) => investment.id === id);
 
    setInvestmentModalData(investment);
 
    toggleShowModal();
  };
 
  const handleCreateInvestment = async () => {
    setInvestmentFormData(initialInvestmentFormData);
 
    setInvestmentFormAction('create');
 
    toggleShowInvestmentForm();
  };
 
  const handleDeleteInvestment = () => {
    removeInvestment(investmentModalData.id);
 
    toggleShowModal();
  };
 
  const handleUpdateInvestment = async (id) => {
    loadInvestmentFormData(id);
 
    setInvestmentFormAction('update');
 
    toggleShowInvestmentForm();
  };
 
  const handleFormSubmit = async (event) => {
    event.preventDefault();
 
    investmentFormData.value = Number(investmentFormData.value) * 100;
 
    investmentFormData.created_at = new Date(
      investmentFormData.created_at + 'T00:00:00-03:00'
    ).toISOString();
 
    investmentFormAction === 'create'
      ? createInvestment(investmentFormData)
      : updateInvestment(investmentFormData);
 
    toggleShowInvestmentForm();
  };
 
  const loadInvestmentFormData = (id) => {
    const investment = investments.find((investment) => investment.id === id);
 
    investment.value = Number(investment.value) / 100;
 
    investment.created_at = formatDate(investment.created_at, 'ymd');
 
    setInvestmentFormData(investment);
  };
 
  return (
    <InvestmentContext.Provider
      value={{
        createInvestment,
        handleCreateInvestment,
        handleDeleteInvestment,
        handleFormSubmit,
        handleLoadModalData,
        handleUpdateInvestment,
        initialInvestmentFormData,
        investmentFormData,
        investmentModalData,
        investments,
        isShowInvestmentForm,
        isShowModal,
        isShowValues,
        loadInvestmentFormData,
        loadInvestments,
        removeInvestment,
        setInvestmentFormData,
        setInvestments,
        setIsShowModal,
        setIsShowValues,
        toggleShowInvestmentForm,
        toggleShowModal,
        toggleShowValues,
        updateInvestment,
      }}
    >
      {children}
    </InvestmentContext.Provider>
  );
}
 
export function useInvestment() {
  return useContext(InvestmentContext);
}
/codes/react/hooks/invest-app/src/context/InvestmenContext.jsx
'use client';
 
import { createContext, useState, useContext } from 'react';
import Storage from '@/services/supabase';
import { formatDate } from '@/lib/format';
 
export const InvestmentContext = createContext({});
 
export function InvestmentProvider({ children }) {
  const initialInvestmentFormData = {
    name: '',
    value: '',
    origin: '',
    category: '',
    interest: '',
    created_at: '',
  };
 
  const [investments, setInvestments] = useState([]);
 
  const [isShowValues, setIsShowValues] = useState(true);
 
  const [isShowModal, setIsShowModal] = useState(false);
 
  const [isShowInvestmentForm, setIsShowInvestmentForm] = useState(false);
 
  const [investmentModalData, setInvestmentModalData] = useState({});
 
  const [investmentFormData, setInvestmentFormData] = useState(
    initialInvestmentFormData
  );
 
  const [investmentFormAction, setInvestmentFormAction] = useState('');
 
  const toggleShowValues = () => {
    setIsShowValues(!isShowValues);
  };
 
  const toggleShowModal = () => {
    setIsShowModal(!isShowModal);
  };
 
  const toggleShowInvestmentForm = () => {
    setIsShowInvestmentForm(!isShowInvestmentForm);
  };
 
  const loadInvestments = async () => {
    const investments = await Storage.read('investments');
 
    setInvestments(investments);
  };
 
  const createInvestment = async (investment) => {
    const newInvestment = await Storage.create('investments', investment);
 
    setInvestments([...investments, newInvestment]);
  };
 
  const updateInvestment = async (investment) => {
    const newInvestments = investments.filter(
      (item) => item.id !== investment.id
    );
 
    setInvestments([...newInvestments, investment]);
 
    Storage.update('investments', investment);
  };
 
  const removeInvestment = (id) => {
    const newInvestments = investments.filter(
      (investment) => investment.id !== id
    );
 
    setInvestments(newInvestments);
 
    Storage.remove('investments', id);
  };
 
  const handleLoadModalData = (id) => {
    const investment = investments.find((investment) => investment.id === id);
 
    setInvestmentModalData(investment);
 
    toggleShowModal();
  };
 
  const handleCreateInvestment = async () => {
    setInvestmentFormData(initialInvestmentFormData);
 
    setInvestmentFormAction('create');
 
    toggleShowInvestmentForm();
  };
 
  const handleDeleteInvestment = () => {
    removeInvestment(investmentModalData.id);
 
    toggleShowModal();
  };
 
  const handleUpdateInvestment = async (id) => {
    loadInvestmentFormData(id);
 
    setInvestmentFormAction('update');
 
    toggleShowInvestmentForm();
  };
 
  const handleFormSubmit = async (event) => {
    event.preventDefault();
 
    investmentFormData.value = Number(investmentFormData.value) * 100;
 
    investmentFormData.created_at = new Date(
      investmentFormData.created_at + 'T00:00:00-03:00'
    ).toISOString();
 
    investmentFormAction === 'create'
      ? createInvestment(investmentFormData)
      : updateInvestment(investmentFormData);
 
    toggleShowInvestmentForm();
  };
 
  const loadInvestmentFormData = (id) => {
    const investment = investments.find((investment) => investment.id === id);
 
    investment.value = Number(investment.value) / 100;
 
    investment.created_at = formatDate(investment.created_at, 'ymd');
 
    setInvestmentFormData(investment);
  };
 
  return (
    <InvestmentContext.Provider
      value={{
        createInvestment,
        handleCreateInvestment,
        handleDeleteInvestment,
        handleFormSubmit,
        handleLoadModalData,
        handleUpdateInvestment,
        initialInvestmentFormData,
        investmentFormData,
        investmentModalData,
        investments,
        isShowInvestmentForm,
        isShowModal,
        isShowValues,
        loadInvestmentFormData,
        loadInvestments,
        removeInvestment,
        setInvestmentFormData,
        setInvestments,
        setIsShowModal,
        setIsShowValues,
        toggleShowInvestmentForm,
        toggleShowModal,
        toggleShowValues,
        updateInvestment,
      }}
    >
      {children}
    </InvestmentContext.Provider>
  );
}
 
export function useInvestment() {
  return useContext(InvestmentContext);
}

Home

/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import { useEffect } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
import { useInvestment } from '@/contexts/InvestmentContext';
import InvestmentForm from '@/components/InvestmentForm';
import Modal from '@/components/Modal';
 
export default function Home() {
  const {
    investments,
    loadInvestments,
    isShowValues,
    toggleShowValues,
    handleCreateInvestment,
  } = useInvestment();
 
  useEffect(() => {
    loadInvestments();
  }, []);
 
  return (
    <>
      <header className="py-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard {...investment} key={investment.id} />
        ))}
      </div>
 
      <div className="fixed bottom-8 right-8">
        <button
          type="button"
          className="new-investment-btn py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
          onClick={() => handleCreateInvestment()}
        >
          +
        </button>
      </div>
 
      <InvestmentForm />
 
      <Modal />
    </>
  );
}
/codes/react/hooks/invest-app/src/app/page.jsx
'use client';
 
import { useEffect } from 'react';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import InvestmentCard from '@/components/InvestmentCard';
import { useInvestment } from '@/contexts/InvestmentContext';
import InvestmentForm from '@/components/InvestmentForm';
import Modal from '@/components/Modal';
 
export default function Home() {
  const {
    investments,
    loadInvestments,
    isShowValues,
    toggleShowValues,
    handleCreateInvestment,
  } = useInvestment();
 
  useEffect(() => {
    loadInvestments();
  }, []);
 
  return (
    <>
      <header className="py-12">
        <div className="float-right" onClick={toggleShowValues}>
          {isShowValues ? <IconEye size={24} /> : <IconEyeOff size={24} />}
        </div>
        <h1 className="text-center text-2xl font-bold">Investimentos</h1>
      </header>
 
      <div className="investments grid grid-cols-3 gap-3">
        {investments.map((investment) => (
          <InvestmentCard {...investment} key={investment.id} />
        ))}
      </div>
 
      <div className="fixed bottom-8 right-8">
        <button
          type="button"
          className="new-investment-btn py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
          onClick={() => handleCreateInvestment()}
        >
          +
        </button>
      </div>
 
      <InvestmentForm />
 
      <Modal />
    </>
  );
}

InvestmentCard

/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
'use client';
 
import Link from 'next/link';
import { IconTrash, IconPencil } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
}) {
  const { isShowValues, handleLoadModalData, handleUpdateInvestment } =
    useInvestment();
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValues ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Origem:</span>
          <span className="investment-origin">{origin}</span>
        </p>
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Categoria:</span>
          <span className="investment-category">{category}</span>
        </p>
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Taxa:</span>
          <span className="investment-interest">{interest}</span>
        </p>
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Data:</span>
          <span className="investment-created_at">
            {formatDate(created_at)}
          </span>
        </p>
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleLoadModalData(id)}
        />
        <IconPencil
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleUpdateInvestment(id)}
        />
      </div>
    </div>
  );
}
/codes/react/hooks/invest-app/src/components/InvestmentCard.jsx
'use client';
 
import Link from 'next/link';
import { IconTrash, IconPencil } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function InvestmentCard({
  id,
  name,
  value,
  origin,
  category,
  interest,
  created_at,
}) {
  const { isShowValues, handleLoadModalData, handleUpdateInvestment } =
    useInvestment();
 
  return (
    <div className="bg-white shadow-md rounded-lg p-4 relative">
      <div className="flex justify-between items-center">
        <Link href={`/investments/${id}`}>
          <h3 className="investment-name text-lg font-semibold text-gray-700">
            {name}
          </h3>
        </Link>
        <p className="investment-value text-lg font-semibold text-gray-700">
          {isShowValues ? formatCurrency(value / 100) : 'R$ ****'}
        </p>
      </div>
      <div className="mt-4">
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Origem:</span>
          <span className="investment-origin">{origin}</span>
        </p>
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Categoria:</span>
          <span className="investment-category">{category}</span>
        </p>
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Taxa:</span>
          <span className="investment-interest">{interest}</span>
        </p>
        <p className="text-sm text-gray-500">
          <span className="font-bold mr-1">Data:</span>
          <span className="investment-created_at">
            {formatDate(created_at)}
          </span>
        </p>
      </div>
      <div className="absolute bottom-4 right-4 inline-flex">
        <IconTrash
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleLoadModalData(id)}
        />
        <IconPencil
          size={20}
          className="text-gray-400 hover:text-gray-500 cursor-pointer"
          onClick={() => handleUpdateInvestment(id)}
        />
      </div>
    </div>
  );
}

InvestmentForm

/codes/react/hooks/invest-app/src/components/InvestmentForm.jsx
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function InvestmentForm() {
  const {
    isShowInvestmentForm,
    toggleShowInvestmentForm,
    investmentFormData,
    setInvestmentFormData,
    handleFormSubmit,
  } = useInvestment();
 
  const handleChange = (event) => {
    let { name, value } = event.target;
 
    setInvestmentFormData({ ...investmentFormData, [name]: value });
  };
 
  return (
    <>
      {isShowInvestmentForm && (
        <div>
          <div
            className="fixed h-full w-full right-0 top-0 bg-black/50 z-10"
            onClick={() => toggleShowInvestmentForm()}
          ></div>
          <div
            className="fixed bottom-0 right-0 top-0 z-[1045] flex w-96 max-w-full flex-col border-none bg-white bg-clip-padding text-neutral-700 shadow-sm outline-none transition duration-300 ease-in-out dark:bg-neutral-800 dark:text-neutral-200 [&[data-te-offcanvas-show]]:transform-none"
            tabIndex={-1}
          >
            <div className="flex justify-between items-center py-3 px-4 border-b dark:border-gray-700">
              <h3 className="font-bold text-gray-800 dark:text-white">
                Investimento
              </h3>
              <button
                type="button"
                className="investment-drawer-close inline-flex flex-shrink-0 justify-center items-center h-8 w-8 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-white text-sm dark:text-gray-500 dark:hover:text-gray-400 dark:focus:ring-gray-700 dark:focus:ring-offset-gray-800"
                onClick={() => toggleShowInvestmentForm()}
              >
                <span className="sr-only">Cadastro de Investimento</span>
                <svg
                  className="w-3.5 h-3.5"
                  width={8}
                  height={8}
                  viewBox="0 0 8 8"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M0.258206 1.00652C0.351976 0.912791 0.479126 0.860131 0.611706 0.860131C0.744296 0.860131 0.871447 0.912791 0.965207 1.00652L3.61171 3.65302L6.25822 1.00652C6.30432 0.958771 6.35952 0.920671 6.42052 0.894471C6.48152 0.868271 6.54712 0.854471 6.61352 0.853901C6.67992 0.853321 6.74572 0.865971 6.80722 0.891111C6.86862 0.916251 6.92442 0.953381 6.97142 1.00032C7.01832 1.04727 7.05552 1.1031 7.08062 1.16454C7.10572 1.22599 7.11842 1.29183 7.11782 1.35822C7.11722 1.42461 7.10342 1.49022 7.07722 1.55122C7.05102 1.61222 7.01292 1.6674 6.96522 1.71352L4.31871 4.36002L6.96522 7.00648C7.05632 7.10078 7.10672 7.22708 7.10552 7.35818C7.10442 7.48928 7.05182 7.61468 6.95912 7.70738C6.86642 7.80018 6.74102 7.85268 6.60992 7.85388C6.47882 7.85498 6.35252 7.80458 6.25822 7.71348L3.61171 5.06702L0.965207 7.71348C0.870907 7.80458 0.744606 7.85498 0.613506 7.85388C0.482406 7.85268 0.357007 7.80018 0.264297 7.70738C0.171597 7.61468 0.119017 7.48928 0.117877 7.35818C0.116737 7.22708 0.167126 7.10078 0.258206 7.00648L2.90471 4.36002L0.258206 1.71352C0.164476 1.61976 0.111816 1.4926 0.111816 1.36002C0.111816 1.22744 0.164476 1.10028 0.258206 1.00652Z"
                    fill="currentColor"
                  />
                </svg>
              </button>
            </div>
            <div className="p-4 overflow-y-auto">
              <form onSubmit={(event) => handleFormSubmit(event)}>
                <input type="hidden" id="id" name="id" />
                <div className="mb-3">
                  <label
                    htmlFor="name"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Nome
                  </label>
                  <input
                    type="text"
                    id="name"
                    name="name"
                    onChange={handleChange}
                    value={investmentFormData.name}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="value"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Valor
                  </label>
                  <input
                    type="number"
                    id="value"
                    name="value"
                    onChange={handleChange}
                    value={investmentFormData.value}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="origin"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Origem
                  </label>
                  <input
                    type="text"
                    id="origin"
                    name="origin"
                    onChange={handleChange}
                    value={investmentFormData.origin}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="category"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Categoria
                  </label>
                  <input
                    type="text"
                    id="category"
                    name="category"
                    onChange={handleChange}
                    value={investmentFormData.category}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="interest"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Taxa
                  </label>
                  <input
                    type="text"
                    id="interest"
                    name="interest"
                    onChange={handleChange}
                    value={investmentFormData.interest}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="created_at"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Data
                  </label>
                  <input
                    type="date"
                    id="created_at"
                    name="created_at"
                    onChange={handleChange}
                    value={investmentFormData.created_at}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div>
                  <button
                    type="submit"
                    className="py-3 px-4 inline-flex w-full justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
                  >
                    Enviar
                  </button>
                </div>
              </form>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
/codes/react/hooks/invest-app/src/components/InvestmentForm.jsx
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function InvestmentForm() {
  const {
    isShowInvestmentForm,
    toggleShowInvestmentForm,
    investmentFormData,
    setInvestmentFormData,
    handleFormSubmit,
  } = useInvestment();
 
  const handleChange = (event) => {
    let { name, value } = event.target;
 
    setInvestmentFormData({ ...investmentFormData, [name]: value });
  };
 
  return (
    <>
      {isShowInvestmentForm && (
        <div>
          <div
            className="fixed h-full w-full right-0 top-0 bg-black/50 z-10"
            onClick={() => toggleShowInvestmentForm()}
          ></div>
          <div
            className="fixed bottom-0 right-0 top-0 z-[1045] flex w-96 max-w-full flex-col border-none bg-white bg-clip-padding text-neutral-700 shadow-sm outline-none transition duration-300 ease-in-out dark:bg-neutral-800 dark:text-neutral-200 [&[data-te-offcanvas-show]]:transform-none"
            tabIndex={-1}
          >
            <div className="flex justify-between items-center py-3 px-4 border-b dark:border-gray-700">
              <h3 className="font-bold text-gray-800 dark:text-white">
                Investimento
              </h3>
              <button
                type="button"
                className="investment-drawer-close inline-flex flex-shrink-0 justify-center items-center h-8 w-8 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-white text-sm dark:text-gray-500 dark:hover:text-gray-400 dark:focus:ring-gray-700 dark:focus:ring-offset-gray-800"
                onClick={() => toggleShowInvestmentForm()}
              >
                <span className="sr-only">Cadastro de Investimento</span>
                <svg
                  className="w-3.5 h-3.5"
                  width={8}
                  height={8}
                  viewBox="0 0 8 8"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M0.258206 1.00652C0.351976 0.912791 0.479126 0.860131 0.611706 0.860131C0.744296 0.860131 0.871447 0.912791 0.965207 1.00652L3.61171 3.65302L6.25822 1.00652C6.30432 0.958771 6.35952 0.920671 6.42052 0.894471C6.48152 0.868271 6.54712 0.854471 6.61352 0.853901C6.67992 0.853321 6.74572 0.865971 6.80722 0.891111C6.86862 0.916251 6.92442 0.953381 6.97142 1.00032C7.01832 1.04727 7.05552 1.1031 7.08062 1.16454C7.10572 1.22599 7.11842 1.29183 7.11782 1.35822C7.11722 1.42461 7.10342 1.49022 7.07722 1.55122C7.05102 1.61222 7.01292 1.6674 6.96522 1.71352L4.31871 4.36002L6.96522 7.00648C7.05632 7.10078 7.10672 7.22708 7.10552 7.35818C7.10442 7.48928 7.05182 7.61468 6.95912 7.70738C6.86642 7.80018 6.74102 7.85268 6.60992 7.85388C6.47882 7.85498 6.35252 7.80458 6.25822 7.71348L3.61171 5.06702L0.965207 7.71348C0.870907 7.80458 0.744606 7.85498 0.613506 7.85388C0.482406 7.85268 0.357007 7.80018 0.264297 7.70738C0.171597 7.61468 0.119017 7.48928 0.117877 7.35818C0.116737 7.22708 0.167126 7.10078 0.258206 7.00648L2.90471 4.36002L0.258206 1.71352C0.164476 1.61976 0.111816 1.4926 0.111816 1.36002C0.111816 1.22744 0.164476 1.10028 0.258206 1.00652Z"
                    fill="currentColor"
                  />
                </svg>
              </button>
            </div>
            <div className="p-4 overflow-y-auto">
              <form onSubmit={(event) => handleFormSubmit(event)}>
                <input type="hidden" id="id" name="id" />
                <div className="mb-3">
                  <label
                    htmlFor="name"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Nome
                  </label>
                  <input
                    type="text"
                    id="name"
                    name="name"
                    onChange={handleChange}
                    value={investmentFormData.name}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="value"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Valor
                  </label>
                  <input
                    type="number"
                    id="value"
                    name="value"
                    onChange={handleChange}
                    value={investmentFormData.value}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="origin"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Origem
                  </label>
                  <input
                    type="text"
                    id="origin"
                    name="origin"
                    onChange={handleChange}
                    value={investmentFormData.origin}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="category"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Categoria
                  </label>
                  <input
                    type="text"
                    id="category"
                    name="category"
                    onChange={handleChange}
                    value={investmentFormData.category}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="interest"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Taxa
                  </label>
                  <input
                    type="text"
                    id="interest"
                    name="interest"
                    onChange={handleChange}
                    value={investmentFormData.interest}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div className="mb-3">
                  <label
                    htmlFor="created_at"
                    className="block text-sm font-medium mb-2 dark:text-white"
                  >
                    Data
                  </label>
                  <input
                    type="date"
                    id="created_at"
                    name="created_at"
                    onChange={handleChange}
                    value={investmentFormData.created_at}
                    className="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
                    required=""
                  />
                </div>
                <div>
                  <button
                    type="submit"
                    className="py-3 px-4 inline-flex w-full justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
                  >
                    Enviar
                  </button>
                </div>
              </form>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
/codes/react/hooks/invest-app/src/components/Modal.jsx
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function Modal() {
  const {
    isShowModal,
    toggleShowModal,
    handleDeleteInvestment,
    investmentModalData,
  } = useInvestment();
 
  return (
    <>
      {isShowModal && (
        <div>
          <div
            className="fixed h-full w-full right-0 top-0 bg-black/50 z-10"
            onClick={() => toggleShowModal()}
          ></div>
          <div className="fixed top-1/3 left-1/2 -translate-x-1/2 z-[60] overflow-x-hidden overflow-y-auto sm:max-w-lg sm:w-full sm:mx-auto flex flex-col bg-white border shadow-sm rounded-xl dark:bg-gray-800 dark:border-gray-700 dark:shadow-slate-700/[.7]">
            <div className="flex justify-between items-center py-3 px-4 border-b dark:border-gray-700">
              <h3 className="font-bold text-gray-800 dark:text-white">
                Remover Investimento
              </h3>
              <button
                type="button"
                className="hs-dropdown-toggle inline-flex flex-shrink-0 justify-center items-center h-8 w-8 rounded-md text-gray-500 hover:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-white transition-all text-sm dark:focus:ring-gray-700 dark:focus:ring-offset-gray-800"
                onClick={toggleShowModal}
              >
                <span className="sr-only">Close</span>
                <svg
                  className="w-3.5 h-3.5"
                  width={8}
                  height={8}
                  viewBox="0 0 8 8"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M0.258206 1.00652C0.351976 0.912791 0.479126 0.860131 0.611706 0.860131C0.744296 0.860131 0.871447 0.912791 0.965207 1.00652L3.61171 3.65302L6.25822 1.00652C6.30432 0.958771 6.35952 0.920671 6.42052 0.894471C6.48152 0.868271 6.54712 0.854471 6.61352 0.853901C6.67992 0.853321 6.74572 0.865971 6.80722 0.891111C6.86862 0.916251 6.92442 0.953381 6.97142 1.00032C7.01832 1.04727 7.05552 1.1031 7.08062 1.16454C7.10572 1.22599 7.11842 1.29183 7.11782 1.35822C7.11722 1.42461 7.10342 1.49022 7.07722 1.55122C7.05102 1.61222 7.01292 1.6674 6.96522 1.71352L4.31871 4.36002L6.96522 7.00648C7.05632 7.10078 7.10672 7.22708 7.10552 7.35818C7.10442 7.48928 7.05182 7.61468 6.95912 7.70738C6.86642 7.80018 6.74102 7.85268 6.60992 7.85388C6.47882 7.85498 6.35252 7.80458 6.25822 7.71348L3.61171 5.06702L0.965207 7.71348C0.870907 7.80458 0.744606 7.85498 0.613506 7.85388C0.482406 7.85268 0.357007 7.80018 0.264297 7.70738C0.171597 7.61468 0.119017 7.48928 0.117877 7.35818C0.116737 7.22708 0.167126 7.10078 0.258206 7.00648L2.90471 4.36002L0.258206 1.71352C0.164476 1.61976 0.111816 1.4926 0.111816 1.36002C0.111816 1.22744 0.164476 1.10028 0.258206 1.00652Z"
                    fill="currentColor"
                  />
                </svg>
              </button>
            </div>
            <div className="p-4 overflow-y-auto">
              <p className="mt-1 text-gray-800 dark:text-gray-400">
                Deseja remover o investimento{' '}
                <span className="investment-name font-semibold">
                  {' '}
                  {investmentModalData.name}
                </span>
                ?
              </p>
            </div>
            <div className="flex justify-end items-center gap-x-2 py-3 px-4 border-t dark:border-gray-700">
              <button
                type="button"
                className="hs-dropdown-toggle py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border font-medium bg-white text-gray-700 shadow-sm align-middle hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-blue-600 transition-all text-sm dark:bg-slate-900 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400 dark:hover:text-white dark:focus:ring-offset-gray-800"
                onClick={toggleShowModal}
              >
                Cancelar
              </button>
              <button
                type="button"
                className="remove-investment-btn py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
                onClick={handleDeleteInvestment}
              >
                Confirmar
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
/codes/react/hooks/invest-app/src/components/Modal.jsx
import { useInvestment } from '@/contexts/InvestmentContext';
 
export default function Modal() {
  const {
    isShowModal,
    toggleShowModal,
    handleDeleteInvestment,
    investmentModalData,
  } = useInvestment();
 
  return (
    <>
      {isShowModal && (
        <div>
          <div
            className="fixed h-full w-full right-0 top-0 bg-black/50 z-10"
            onClick={() => toggleShowModal()}
          ></div>
          <div className="fixed top-1/3 left-1/2 -translate-x-1/2 z-[60] overflow-x-hidden overflow-y-auto sm:max-w-lg sm:w-full sm:mx-auto flex flex-col bg-white border shadow-sm rounded-xl dark:bg-gray-800 dark:border-gray-700 dark:shadow-slate-700/[.7]">
            <div className="flex justify-between items-center py-3 px-4 border-b dark:border-gray-700">
              <h3 className="font-bold text-gray-800 dark:text-white">
                Remover Investimento
              </h3>
              <button
                type="button"
                className="hs-dropdown-toggle inline-flex flex-shrink-0 justify-center items-center h-8 w-8 rounded-md text-gray-500 hover:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-white transition-all text-sm dark:focus:ring-gray-700 dark:focus:ring-offset-gray-800"
                onClick={toggleShowModal}
              >
                <span className="sr-only">Close</span>
                <svg
                  className="w-3.5 h-3.5"
                  width={8}
                  height={8}
                  viewBox="0 0 8 8"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M0.258206 1.00652C0.351976 0.912791 0.479126 0.860131 0.611706 0.860131C0.744296 0.860131 0.871447 0.912791 0.965207 1.00652L3.61171 3.65302L6.25822 1.00652C6.30432 0.958771 6.35952 0.920671 6.42052 0.894471C6.48152 0.868271 6.54712 0.854471 6.61352 0.853901C6.67992 0.853321 6.74572 0.865971 6.80722 0.891111C6.86862 0.916251 6.92442 0.953381 6.97142 1.00032C7.01832 1.04727 7.05552 1.1031 7.08062 1.16454C7.10572 1.22599 7.11842 1.29183 7.11782 1.35822C7.11722 1.42461 7.10342 1.49022 7.07722 1.55122C7.05102 1.61222 7.01292 1.6674 6.96522 1.71352L4.31871 4.36002L6.96522 7.00648C7.05632 7.10078 7.10672 7.22708 7.10552 7.35818C7.10442 7.48928 7.05182 7.61468 6.95912 7.70738C6.86642 7.80018 6.74102 7.85268 6.60992 7.85388C6.47882 7.85498 6.35252 7.80458 6.25822 7.71348L3.61171 5.06702L0.965207 7.71348C0.870907 7.80458 0.744606 7.85498 0.613506 7.85388C0.482406 7.85268 0.357007 7.80018 0.264297 7.70738C0.171597 7.61468 0.119017 7.48928 0.117877 7.35818C0.116737 7.22708 0.167126 7.10078 0.258206 7.00648L2.90471 4.36002L0.258206 1.71352C0.164476 1.61976 0.111816 1.4926 0.111816 1.36002C0.111816 1.22744 0.164476 1.10028 0.258206 1.00652Z"
                    fill="currentColor"
                  />
                </svg>
              </button>
            </div>
            <div className="p-4 overflow-y-auto">
              <p className="mt-1 text-gray-800 dark:text-gray-400">
                Deseja remover o investimento{' '}
                <span className="investment-name font-semibold">
                  {' '}
                  {investmentModalData.name}
                </span>
                ?
              </p>
            </div>
            <div className="flex justify-end items-center gap-x-2 py-3 px-4 border-t dark:border-gray-700">
              <button
                type="button"
                className="hs-dropdown-toggle py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border font-medium bg-white text-gray-700 shadow-sm align-middle hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-blue-600 transition-all text-sm dark:bg-slate-900 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400 dark:hover:text-white dark:focus:ring-offset-gray-800"
                onClick={toggleShowModal}
              >
                Cancelar
              </button>
              <button
                type="button"
                className="remove-investment-btn py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
                onClick={handleDeleteInvestment}
              >
                Confirmar
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}

Editar esta página