Skip to content

Modals


In this section, we will create the Modals for the frontend application. We use the Modal component that we created earlier.

Create Account Modal

We start with Create Account Modal that will be used to connect to the ZilPay wallet as well as access the smart contract.

It uses Input and Button components. It uses CheckBox for selecting the user role. A button is presented for connecting ZilPay when required.

The createAccountTransition function is used.

import React, { useEffect, useState } from "react";
import ContextContainer from "../functions/contextContainer";
import createUserTransition from "../functions/createUserTransition";
import Button from "./componentButton";
import Input from "./componentInput";
import Modal from "./componentModal";
import Tick from "./componentTick";

type props = {
  showSignUp: boolean;
  setShowSignUp(visible: boolean): void;
};

const CreateAccountModal: React.FC<props> = (props) => {
  const { showSignUp, setShowSignUp } = props;
  const [name, setName] = useState<string | undefined>(undefined);
  const [userRole, setUserRole] = useState<string | undefined>("host");
  const { zilPay, contract } = ContextContainer.useContainer();

  const createUser = async () => {
    const role = userRole === "host" ? "1" : "0";
    createUserTransition(contract, zilPay, name, role);
  };

  const connectZilPay = async () => {
    await zilPay.wallet.connect();
    window.location.reload();
  };

  useEffect(() => {
    setName(undefined);
    setUserRole("host");
  }, [setShowSignUp]);

  return (
    <Modal
      title="Create Account"
      visible={showSignUp}
      setVisible={setShowSignUp}
      buttonText={"Create Account"}
      onClick={createUser}
    >
      <>
        {!zilPay.wallet.isConnect && (
          <>
            <h4 className="text-xs font-semibold text-gray-500 tracking-wide uppercase py-4">
              ZilPay
            </h4>
            <Button
              text={"Connect ZilPay"}
              padding
              onClick={connectZilPay}
              modal
            />
          </>
        )}
        <Input name="Your name" value={name} setValue={setName} />
        <h4 className="text-xs font-semibold text-gray-500 tracking-wide uppercase py-4">
          Please select one
        </h4>
        <div className="flex gap-12 mb-8">
          <div
            className="flex justify-center items-center cursor-pointer"
            onClick={() => setUserRole("host")}
          >
            <p className="text-lg text-gray-800 pr-4">Host</p>
            <div
              className={`p-1 bg-gray-200 rounded-lg w-8 h-8 hover:scale-95 transform transition-all ${
                userRole === "host" ? "" : "hover:bg-gray-300"
              }`}
            >
              <div
                className={`w-full h-full rounded transition-colors text-transparent ${
                  userRole === "host" ? "bg-gray-900 text-gray-200" : ""
                }`}
              >
                {userRole === "host" && <Tick />}
              </div>
            </div>
          </div>
          <div
            className="flex justify-center items-center cursor-pointer"
            onClick={() => setUserRole("renter")}
          >
            <p className="text-lg text-gray-800 pr-4">Rent</p>
            <div
              className={`p-1 bg-gray-200 rounded-lg w-8 h-8 hover:scale-95 transform transition-all ${
                userRole !== "host" ? "" : "hover:bg-gray-300"
              }`}
            >
              <div
                className={`w-full h-full rounded transition-colors text-transparent ${
                  userRole !== "host" ? "bg-gray-900 text-gray-200" : ""
                }`}
              >
                {userRole !== "host" && <Tick />}
              </div>
            </div>
          </div>
        </div>
      </>
    </Modal>
  );
};

export default CreateAccountModal;

/src/components/componentCreateAccountModal.tsx


Create Listing Modal

We now get to the Create Listing Modal that will be used by host users to post new listings.

It uses Input and Button components. It uses AmenitiesInput for selecting the available amenities. A button is presented for connecting ZilPay when required.

The createListingTransition function is used.

import React, { useEffect, useState } from "react";
import ContextContainer from "../functions/contextContainer";
import createListingTransition from "../functions/createListingTransition";
import AmenitiesInput from "./componentAmenitiesInput";
import Input from "./componentInput";
import Modal from "./componentModal";

type props = {
  showCreateListing: boolean;
  setShowCreateListing(visible: boolean): void;
};

const CreateListingModal: React.FC<props> = (props) => {
  const { showCreateListing, setShowCreateListing } = props;

  const [name, setName] = useState<string | undefined>(undefined);
  const [description, setDescription] = useState<string | undefined>(undefined);
  const [price, setPrice] = useState<string | undefined>(undefined);
  const [rooms, setRooms] = useState<string | undefined>(undefined);
  const [bathrooms, setBathrooms] = useState<string | undefined>(undefined);
  const [location, setLocation] = useState<string | undefined>(undefined);
  const [image, setImage] = useState<string | undefined>(undefined);

  const [wifi, setWifi] = useState<boolean>(false);
  const [kitchen, setKitchen] = useState<boolean>(false);
  const [tv, setTv] = useState<boolean>(false);
  const [laundry, setLaundry] = useState<boolean>(false);
  const [hvac, setHvac] = useState<boolean>(false);

  const { contract, zilPay } = ContextContainer.useContainer();

  const createListing = () => {
    if (
      !name ||
      !description ||
      !price ||
      !rooms ||
      !bathrooms ||
      !location ||
      !image
    )
      return;
    createListingTransition(
      contract,
      zilPay,
      name,
      description,
      price,
      rooms,
      bathrooms,
      image,
      location,
      wifi,
      kitchen,
      tv,
      laundry,
      hvac,
    );
  };

  useEffect(() => {
    setName(undefined);
    setDescription(undefined);
    setPrice(undefined);
    setRooms(undefined);
    setBathrooms(undefined);
    setLocation(undefined);
    setImage(undefined);
    setWifi(false);
    setKitchen(false);
    setTv(false);
    setLaundry(false);
    setHvac(false);
  }, [showCreateListing]);

  return (
    <Modal
      title="Create Listing"
      visible={showCreateListing}
      setVisible={setShowCreateListing}
      buttonText={"Create"}
      onClick={createListing}
    >
      <Input name="Name" value={name} setValue={setName} />
      <Input name="Description" value={description} setValue={setDescription} />
      <Input name="Rooms" value={rooms} type="number" setValue={setRooms} />
      <Input
        name="Bathrooms"
        value={bathrooms}
        type="number"
        setValue={setBathrooms}
      />
      <Input
        name="Price (ZIL)"
        unit="per night"
        value={price}
        type="number"
        setValue={setPrice}
      />
      <Input name="Image URL" value={image} type="text" setValue={setImage} />
      <Input
        name="Google Maps Plus Code"
        value={location}
        type="text"
        setValue={setLocation}
      />
      <AmenitiesInput
        {...{
          wifi,
          setWifi,
          kitchen,
          setKitchen,
          tv,
          setTv,
          laundry,
          setLaundry,
          hvac,
          setHvac,
        }}
      />
    </Modal>
  );
};

export default CreateListingModal;

/src/components/componentCreateListingModal.tsx


Manage Listing Modal

We now get to the Create Listing Modal that will be used by host users to post new listings.

It uses Input and Button components. It uses AmenitiesInput for selecting the available amenities. A button is presented for connecting ZilPay when required.

The deleteListingTransition, updateListingTransition, and claimRentTransition functions are called as required.

import React, { useEffect, useState } from "react";
import claimRentTransition from "../functions/claimRentTransition";
import ContextContainer from "../functions/contextContainer";
import deleteListingTransition from "../functions/deleteListingTransition";
import updateListingTransition from "../functions/updateListingTransition";
import AmenitiesInput from "./componentAmenitiesInput";
import Button from "./componentButton";
import Input from "./componentInput";
import Modal from "./componentModal";

type props = {
  modalListing: any;
  showManageListing: boolean;
  setShowManageListing(visible: boolean): void;
};

const ManageListingModal: React.FC<props> = (props) => {
  const { showManageListing, setShowManageListing, modalListing } = props;
  const { id, accumulated_rent } = modalListing;

  const [name, setName] = useState<string | undefined>(undefined);
  const [description, setDescription] = useState<string | undefined>(undefined);
  const [price, setPrice] = useState<string | undefined>(undefined);
  const [rooms, setRooms] = useState<string | undefined>(undefined);
  const [bathrooms, setBathrooms] = useState<string | undefined>(undefined);
  const [location, setLocation] = useState<string | undefined>(undefined);
  const [image, setImage] = useState<string | undefined>(undefined);

  const [wifi, setWifi] = useState<boolean>(false);
  const [kitchen, setKitchen] = useState<boolean>(false);
  const [tv, setTv] = useState<boolean>(false);
  const [laundry, setLaundry] = useState<boolean>(false);
  const [hvac, setHvac] = useState<boolean>(false);

  const { contract, zilPay } = ContextContainer.useContainer();

  const updateListing = () => {
    if (
      !name ||
      !description ||
      !price ||
      !rooms ||
      !bathrooms ||
      !location ||
      !image
    )
      return;
    updateListingTransition(
      contract,
      zilPay,
      id,
      name,
      description,
      price,
      rooms,
      bathrooms,
      image,
      location,
      wifi,
      kitchen,
      tv,
      laundry,
      hvac,
    );
  };

  const claimRent = () => {
    claimRentTransition(contract, zilPay, id);
    setShowManageListing(false);
  };

  const deleteListing = () => {
    deleteListingTransition(contract, zilPay, id);
    setShowManageListing(false);
  };

  useEffect(() => {
    setName(modalListing.name);
    setDescription(modalListing.description);
    setPrice(modalListing.price);
    setRooms(modalListing.rooms);
    setBathrooms(modalListing.bathrooms);
    setLocation(modalListing.location);
    setImage(modalListing.image);
    setWifi(modalListing.amenities.wifi);
    setKitchen(modalListing.amenities.kitchen);
    setTv(modalListing.amenities.tv);
    setLaundry(modalListing.amenities.laundry);
    setHvac(modalListing.amenities.hvac);
  }, [showManageListing]);

  return (
    <Modal
      title="Manage Listing"
      visible={showManageListing}
      setVisible={setShowManageListing}
      buttonText={"Update Listing"}
      onClick={updateListing}
    >
      <>
        <h4 className="text-sm font-semibold text-gray-500 tracking-wide uppercase py-4">
          Accumulated Rent
        </h4>
        <div className="flex justify-between items-center pb-8">
          <p className="text-2xl ">{accumulated_rent}</p>
          <Button text={"Claim Rent"} onClick={claimRent} />
        </div>
      </>
      <>
        <h4 className="text-sm font-semibold text-gray-500 tracking-wide uppercase py-4">
          Delete Listing
        </h4>
        <Button
          text={"Delete Listing"}
          onClick={deleteListing}
          alert
          padding
          modal
        />
      </>
      <Input name="Name" value={name} setValue={setName} />
      <Input name="Description" value={description} setValue={setDescription} />
      <Input name="Rooms" value={rooms} type="number" setValue={setRooms} />
      <Input
        name="Bathrooms"
        value={bathrooms}
        type="number"
        setValue={setBathrooms}
      />
      <Input
        name="Price (ZIL)"
        unit="per night"
        value={price}
        type="number"
        setValue={setPrice}
      />
      <Input name="Image URL" value={image} type="text" setValue={setImage} />
      <Input
        name="Google Maps Plus Code"
        value={location}
        type="text"
        setValue={setLocation}
      />
      <AmenitiesInput
        {...{
          wifi,
          setWifi,
          kitchen,
          setKitchen,
          tv,
          setTv,
          laundry,
          setLaundry,
          hvac,
          setHvac,
        }}
      />
    </Modal>
  );
};

export default ManageListingModal;

/src/components/componentManageListingModal.tsx