Frontend for Apartment Rental DApp (React + Web3.js)

Frontend for Apartment Rental DApp (React + Web3.js)

This frontend connects to the ApartmentRental smart contract, allowing landlords and tenants to interact with the lease agreement.

Read this first: Smart Contract for Apartment Rental & Payments (Solidity)


1. Setup the Project

bash

npx create-react-app apartment-rental-dapp
cd apartment-rental-dapp
npm install web3 @metamask/detect-provider @chakra-ui/react ethers

2. Key Components

  • Connect Wallet (MetaMask)
  • Landlord Dashboard (Create lease, refund deposit)
  • Tenant Dashboard (Pay rent, terminate lease)

3. Full Frontend Code

App.js (Main Component)

jsx

import { useState, useEffect } from 'react';
import { ChakraProvider, Button, Box, Heading, Input, Text, VStack, HStack, Alert, AlertIcon } from '@chakra-ui/react';
import Web3 from 'web3';
import ApartmentRentalABI from './ApartmentRentalABI.json'; // Import ABI

function App() {
  const [web3, setWeb3] = useState(null);
  const [account, setAccount] = useState('');
  const [contract, setContract] = useState(null);
  const [isLandlord, setIsLandlord] = useState(false);
  const [isTenant, setIsTenant] = useState(false);
  const [leaseDetails, setLeaseDetails] = useState(null);

  // Contract Address (Replace with your deployed address)
  const CONTRACT_ADDRESS = "0x123...YourContractAddress";

  // Initialize Web3 and Contract
  useEffect(() => {
    const initWeb3 = async () => {
      if (window.ethereum) {
        const web3Instance = new Web3(window.ethereum);
        setWeb3(web3Instance);
        
        const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
        setAccount(accounts[0]);
        
        const contractInstance = new web3Instance.eth.Contract(
          ApartmentRentalABI,
          CONTRACT_ADDRESS
        );
        setContract(contractInstance);

        // Check if user is landlord or tenant
        const landlord = await contractInstance.methods.landlord().call();
        setIsLandlord(accounts[0].toLowerCase() === landlord.toLowerCase());

        const tenant = await contractInstance.methods.tenant().call();
        setIsTenant(accounts[0].toLowerCase() === tenant.toLowerCase());

        // Load lease details
        if (tenant !== "0x0000000000000000000000000000000000000000") {
          const details = {
            rentAmount: await contractInstance.methods.rentAmount().call(),
            securityDeposit: await contractInstance.methods.securityDeposit().call(),
            leaseStart: await contractInstance.methods.leaseStart().call(),
            leaseEnd: await contractInstance.methods.leaseEnd().call(),
            isActive: await contractInstance.methods.isLeaseActive().call(),
          };
          setLeaseDetails(details);
        }
      } else {
        alert("Please install MetaMask!");
      }
    };
    initWeb3();
  }, []);

  // Sign Lease (Tenant)
  const signLease = async () => {
    const value = Web3.utils.toWei(
      (leaseDetails.rentAmount + leaseDetails.securityDeposit).toString(), 
      'ether'
    );
    await contract.methods.signLease().send({ from: account, value });
    alert("Lease signed successfully!");
  };

  // Pay Rent (ETH)
  const payRent = async (month) => {
    const value = Web3.utils.toWei(leaseDetails.rentAmount.toString(), 'ether');
    await contract.methods.payRent(month).send({ from: account, value });
    alert(`Rent for month ${month} paid!`);
  };

  // Refund Deposit (Landlord)
  const refundDeposit = async (deductions) => {
    await contract.methods.refundDeposit(deductions).send({ from: account });
    alert("Deposit refunded!");
  };

  // Terminate Lease
  const terminateLease = async () => {
    await contract.methods.terminateLease().send({ from: account });
    alert("Lease terminated!");
  };

  return (
    <ChakraProvider>
      <Box p={8}>
        <Heading mb={6}>🏠 Decentralized Apartment Rental</Heading>
        
        {!account ? (
          <Button onClick={() => window.ethereum.request({ method: 'eth_requestAccounts' })}>
            Connect MetaMask
          </Button>
        ) : (
          <VStack spacing={6} align="start">
            <Text>Connected as: {account}</Text>
            
            {isLandlord && (
              <Box borderWidth="1px" p={4} borderRadius="md">
                <Heading size="md">👔 Landlord Dashboard</Heading>
                {leaseDetails && leaseDetails.isActive ? (
                  <Button mt={2} onClick={() => terminateLease()}>
                    Terminate Lease (Penalty: 1 Month Rent)
                  </Button>
                ) : (
                  <Button mt={2} onClick={() => refundDeposit(0)}>
                    Refund Deposit
                  </Button>
                )}
              </Box>
            )}

            {isTenant && leaseDetails && (
              <Box borderWidth="1px" p={4} borderRadius="md">
                <Heading size="md">👤 Tenant Dashboard</Heading>
                <Text>Rent: {Web3.utils.fromWei(leaseDetails.rentAmount, 'ether')} ETH/month</Text>
                <Text>Lease End: {new Date(leaseDetails.leaseEnd * 1000).toLocaleDateString()}</Text>
                
                <Button mt={2} onClick={() => payRent(1)}>Pay Rent (ETH)</Button>
                <Button mt={2} onClick={() => terminateLease()}>Terminate Lease (Lose Deposit)</Button>
              </Box>
            )}

            {!isLandlord && !isTenant && (
              <Alert status="info">
                <AlertIcon />
                You are not the landlord or tenant for this lease.
              </Alert>
            )}
          </VStack>
        )}
      </Box>
    </ChakraProvider>
  );
}

export default App;

4. Contract ABI (ApartmentRentalABI.json)

Paste the ABI from Remix/your compiled contract:

json

[
  {
    "inputs": [
      {"internalType": "uint256","name": "_rentAmount","type": "uint256"},
      {"internalType": "uint256","name": "_securityDeposit","type": "uint256"},
      {"internalType": "uint256","name": "_leaseDurationMonths","type": "uint256"}
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  // ... (Include ALL ABI functions from your contract)
]

5. Key Features

✅ MetaMask Wallet Integration
✅ Landlord & Tenant Views
✅ ETH Payments (Easy to add USDT with payRentERC20)
✅ Responsive UI with Chakra UI


6. How to Run

bash

npm start

Open http://localhost:3000 and connect MetaMask.