diff --git a/packages/nextjs/.env.example b/packages/nextjs/.env.example index c8d03d7..6769588 100644 --- a/packages/nextjs/.env.example +++ b/packages/nextjs/.env.example @@ -11,3 +11,8 @@ # More info: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables NEXT_PUBLIC_ALCHEMY_API_KEY= NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= + +NEXT_PUBLIC_FACTORY_CONTRACT_ADDRESS="" # Polygon Mumbai +NEXT_PUBLIC_PAYROLL_CONTRACT_ADDRESS="" # Polygon Mumbai +NEXT_PUBLIC_LOCAL_CHAIN_ID=0 # REPLACE WITH LOCAL DEV CHAIN +NEXT_PUBLIC_TESTNET_CHAIN_ID=80001 # Polygon Mumbai diff --git a/packages/nextjs/components/dash-wind/features/employees/index.tsx b/packages/nextjs/components/dash-wind/features/employees/index.tsx index ead08d2..f834c21 100644 --- a/packages/nextjs/components/dash-wind/features/employees/index.tsx +++ b/packages/nextjs/components/dash-wind/features/employees/index.tsx @@ -6,6 +6,14 @@ import TitleCard from "../../components/Cards/TitleCard"; import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from "../../utils/globalConstantUtil"; // import { showNotification } from "../common/headerSlice"; import { openModal } from "../common/modalSlice"; + +/*-------------------------------------*/ +// Kaz & Trevor +// uncomment +// import { useContractRead } from "wagmi"; + +/*-------------------------------------*/ + import TrashIcon from "@heroicons/react/24/outline/TrashIcon"; import { /*MyState,*/ @@ -30,13 +38,66 @@ const TopSideButtons = () => { ); }; +/*-------------------------------------*/ +// Kaz & Trevor +// uncomment +// const chainId = process.env.NEXT_PUBLIC_TARGET_LOCAL_CHAIN +// ? process.env.NEXT_PUBLIC_LOCAL_CHAIN_ID +// : process.env.NEXT_PUBLIC_TESTNET_CHAIN_ID; +/*-------------------------------------*/ + function Employees() { + /*-------------------------------------*/ + // Kaz & Trevor + // dummy employee data const [employees] = useState(EMPLOYEES); + /*-------------------------------------*/ + // const {} = useMySelector((state: MyState) => state.employees); const dispatch = useMyDispatch(); const router = useRouter(); + /*-------------------------------------*/ + // Kaz & Trevor + // Component responsible for displaying table of employees on the employer dashboard + /** NOTE + * Employee addresses will be pulled from contract + * Addresses used to find employee data object in DB (dummy data right now) + * One array of all employees will be created + * This array will be saved in global state + * This will allow for access to employee data in other components: EmployeeProfile, + */ + + // uncomment below + // const { + // data: salariedEmployeeAddresses, // address[] + // isError, + // isLoading, + // } = useContractRead({ + // address: process.env.NEXT_PUBLIC_PAYROLL_CONTRACT_ADDRESS, + // abi: payrollContractAbi, + // functionName: "getSalariedEmployees", + // chainId: Number(chainId), + // }); + + // const { + // data: hourlyEmployeeAddresses, // address[] + // isError, + // isLoading, + // } = useContractRead({ + // address: process.env.NEXT_PUBLIC_PAYROLL_CONTRACT_ADDRESS, + // abi: payrollContractAbi, + // functionName: "getHourlyEmployees", + // chainId: Number(chainId), + // }); + + // match each employee address with corresponding employee in dummy data + // function getEmployeesFromDB() { + // // ... + // } + /*-------------------------------------*/ + // useEffect(() => { // dispatch(getLeadsContent()); // }, [dispatch]); @@ -50,6 +111,11 @@ function Employees() { }; const deleteCurrentLead = (e: MouseEvent, index: number) => { + /*-------------------------------------*/ + // Kaz & Trevor + // this function will be responsible for deleting an employee + /*-------------------------------------*/ + e.stopPropagation(); dispatch( diff --git a/packages/nextjs/components/dash-wind/features/user/Login.tsx b/packages/nextjs/components/dash-wind/features/user/Login.tsx index 74f3d13..e4aa292 100644 --- a/packages/nextjs/components/dash-wind/features/user/Login.tsx +++ b/packages/nextjs/components/dash-wind/features/user/Login.tsx @@ -5,7 +5,10 @@ import InputText from "../../components/Input/InputText"; import ErrorText from "../../components/Typography/ErrorText"; import { UpdateFormValues } from "../../types/FormTypes"; import LandingIntro from "./LandingIntro"; -import { setIsConnected } from "~~/auth/authSlice"; +import { Address, createWalletClient, custom } from "viem"; +import { polygonMumbai } from "viem/chains"; +import { useContractRead } from "wagmi"; +import { setIsAdmin, setIsConnected } from "~~/auth/authSlice"; import { web3auth } from "~~/auth/web3auth"; import { MyState, useMyDispatch, useMySelector } from "~~/components/dash-wind/app/store"; @@ -15,6 +18,10 @@ function Login() { emailId: "", }; + const chainId = process.env.NEXT_PUBLIC_TARGET_LOCAL_CHAIN + ? process.env.NEXT_PUBLIC_LOCAL_CHAIN_ID + : process.env.NEXT_PUBLIC_TESTNET_CHAIN_ID; + // const [loading, setLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(""); const [loginObj, setLoginObj] = useState(INITIAL_LOGIN_OBJ); @@ -23,15 +30,61 @@ function Login() { const router = useRouter(); const dispatch = useMyDispatch(); + /*-------------------------------------*/ + // Kaz & Trevor + // getOwner address to test against user's address + // need to see what shape `owner` will be on return + const { + data: owner, + // isError, + // isLoading, + } = useContractRead({ + address: process.env.NEXT_PUBLIC_PAYROLL_CONTRACT_ADDRESS, + // abi: payrollContractAbi, + functionName: "getOwner", + chainId: Number(chainId), + }); + /*-------------------------------------*/ + + /*-------------------------------------*/ + // Kaz & Trevor + // + const { + data: isEmployee, + // isError, + // isLoading, + } = useContractRead({ + address: process.env.NEXT_PUBLIC_PAYROLL_CONTRACT_ADDRESS, + // abi: payrollContractAbi, + functionName: "doesEmployeeExist", + args: [ + /* problem: figure out how to getAccount() address here */ + ], + chainId: Number(chainId), + }); + /*-------------------------------------*/ + // Web3Auth async function login() { if (isConnected) { + await determineIfAccountIsAdmin(); + if (!isEmployee) { + // until the hook is working, this is going to prevent us from being directed to the dashboard + return; + } router.push("/dapp/dashboard"); + return; } + try { await web3auth.connect(); if (web3auth.connected) { dispatch(setIsConnected({ isConnected: true })); + await determineIfAccountIsAdmin(); + if (!isEmployee) { + // until the hook is working, this is going to prevent us from being directed to the dashboard + return; + } router.push("/dapp/dashboard"); } } catch (error) { @@ -39,6 +92,44 @@ function Login() { } } + async function determineIfAccountIsAdmin() { + // set loading === true ??? + const address = await getAccounts(); + if (!address) { + console.error("from determineIfAccountIsAdmin - address is undefined"); + return; + } + + if (!owner) { + console.error("From determineIfAccountIsAdmin: ownerData from Payroll Contract is undefined"); + return; + } + + /*-------------------------------------*/ + // Kaz & Trevor + // need to see what shape `owner` will be on return + const isAdmin = address === owner ? true : false; + dispatch(setIsAdmin({ isAdmin: isAdmin })); + /*-------------------------------------*/ + // set loading === false ??? + } + + async function getAccounts() { + if (!web3auth.provider) { + console.log("from login - getAccounts: provider not defined"); + return; + } + const client = createWalletClient({ + // account: privateKeyToAccount('0x...'); // from viem + chain: polygonMumbai, + transport: custom(web3auth.provider), + }); + + // Get user's public address + const [address] = await client.getAddresses(); + return address as Address; + } + const submitForm = (e: React.FormEvent) => { e.preventDefault(); setErrorMessage(""); diff --git a/packages/nextjs/components/web-3-crew/employeeProfile/EmployeeProfile.tsx b/packages/nextjs/components/web-3-crew/employeeProfile/EmployeeProfile.tsx index e6db779..c6f7f68 100644 --- a/packages/nextjs/components/web-3-crew/employeeProfile/EmployeeProfile.tsx +++ b/packages/nextjs/components/web-3-crew/employeeProfile/EmployeeProfile.tsx @@ -30,6 +30,7 @@ function EmployeeProfile({ id }: { id: string }) { // const dispatch = useMyDispatch(); function getEmployee(id: string) { + // Eventually: pull global employee state, filter, find, and pass into EditProfile & ViewProfile const employee = EMPLOYEES.filter(e => e.id === id)[0]; return employee; } @@ -38,7 +39,6 @@ function EmployeeProfile({ id }: { id: string }) { setEditMode(prev => !prev); } - // Call API to update profile settings changes // const updateProfile = () => { // dispatch(showNotification({ message: "Profile Updated", status: 1 })); // }; diff --git a/packages/nextjs/components/web-3-crew/register-page/DeployForm.tsx b/packages/nextjs/components/web-3-crew/register-page/DeployForm.tsx index 677742e..acbef6f 100644 --- a/packages/nextjs/components/web-3-crew/register-page/DeployForm.tsx +++ b/packages/nextjs/components/web-3-crew/register-page/DeployForm.tsx @@ -13,6 +13,9 @@ const payrollFactoryAddress = ""; const payrollFactoryABI: Abi = []; export default function DeployForm({ ownerAddress }: props) { + /*-------------------------------------*/ + // Kaz & Trevor + // deploy company contract after registration of account const { config } = usePrepareContractWrite({ address: payrollFactoryAddress, abi: payrollFactoryABI, @@ -27,6 +30,7 @@ export default function DeployForm({ ownerAddress }: props) { }); const { data, isLoading, isSuccess, write } = useContractWrite(config); + /*-------------------------------------*/ return (