namillum
Version:
Bubble Protocol SDK
527 lines (442 loc) • 14.9 kB
Markdown
---
id: dev-rentonzilliqa-components
title: Components
keywords:
- react
- rentonzilliqa
- components
- frontend
description: Creating the React Components for the RentOnZilliqa frontend application
---
---
In this section, we will build all the components that will be used on the frontend application.
## General Components
### Button
We start with a basic Button component in [`/src/components/componentButton.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentButton.tsx) with a bunch of options for modifying it based on the usage.
```tsx
import React from "react";
type props = {
text: string;
onClick(e: any): void;
white?: boolean;
header?: boolean;
modal?: boolean;
padding?: boolean;
alert?: boolean;
};
const Button: React.FC<props> = (props) => {
const {
text,
white = false,
modal = false,
onClick,
padding = false,
alert = false,
} = props;
const colours = white
? "text-gray-900 bg-white"
: alert
? "text-white bg-red-600"
: "text-white bg-gray-900";
return (
<button
className={`font-medium py-3 text-sm lg:text-base rounded-button shadow-button ${colours} ${
modal ? "w-full lg:text-base" : "px-3 lg:px-6"
} ${padding ? "mb-10" : ""}`}
{...{ onClick }}
>
{text}
</button>
);
};
export default Button;
```
[/src/components/componentButton.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentButton.tsx)
<br/>
### Header
We then create a Header component in [`/src/components/componentHeader.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentHeader.tsx) to be used on all pages.
```tsx
import React from "react";
import { Link } from "react-router-dom";
import Button from "./componentButton";
type props = {
setShowSignUp(showSignUp: boolean): void;
};
const Header: React.FC<props> = (props) => {
const { setShowSignUp } = props;
return (
<header className="bg-gray-900 sticky top-0 z-10">
<div className="container mx-auto px-4 lg:px-2 py-3 flex justify-between items-center">
<Link
className="text-white text-2xl font-medium cursor-pointer"
to="/listings"
>
RentOnZilliqa
</Link>
<Button
text={"Create Account"}
onClick={() => setShowSignUp(true)}
white
header
/>
</div>
</header>
);
};
export default Header;
```
[/src/components/componentHeader.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentHeader.tsx)
<br/>
### Modal
We create a Modal component at [`/src/components/componentModal.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentModal.tsx). Most transitions take place via a modal. This component takes care of the basic Modal functionality and styling.
The `title`; main button set to `buttonText`; dismiss button; and overlay are part of this component.
The `children` passed to this component are the content in the modal.
The `onClick` function will be called when the main button is clicked.
```tsx
import React, { useEffect } from "react";
import Button from "./componentButton";
type props = {
title: string;
children: JSX.Element | JSX.Element[];
setVisible(visible: boolean): void;
visible: boolean;
buttonText: string;
onClick(): void;
};
const Modal: React.FC<props> = (props) => {
const { title, children, setVisible, visible, buttonText, onClick } = props;
useEffect(() => {
document.onkeydown = (event: KeyboardEvent) => {
if (event.key === "Enter") {
event.preventDefault();
onClick();
}
};
}, []);
return (
<div
className={
"w-screen h-screen bg-black bg-opacity-25 fixed top-0 left-0 z-20 transition-all"
}
style={
visible
? {
opacity: 1,
visibility: "visible",
transform: "translateY(0)",
}
: {
opacity: 0,
visibility: "hidden",
transform: "translateY(30px)",
}
}
onClick={() => setVisible(false)}
>
<div className="w-full h-full flex justify-center items-center px-4 lg:px-2 py-2">
<div
className="w-full lg:w-1/3 bg-white shadow-xl rounded-2xl max-h-full flex flex-col"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center p-8">
<p className="text-xl font-bold text-gray-900">{title}</p>
<button
className="p-1 rounded hover:bg-gray-100 transition-colors -mr-1"
onClick={() => setVisible(false)}
>
<svg
className="w-6 h-6 text-gray-700"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<div className="w-full px-8 pt-0 overflow-y-scroll flex-grow">
{children}
</div>
<div className="p-8">
<Button
modal
text={buttonText}
onClick={(e: any) => {
onClick();
setVisible(false);
}}
/>
</div>
</div>
</div>
</div>
);
};
export default Modal;
```
[/src/components/componentModal.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentModal.tsx)
<br/>
### ListingCard
We create a ListingCard component at [`/src/components/componentListingCard.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentListingCard.tsx). This component creates the listing card used on the listings page.
```tsx
import React from "react";
type props = {
id: string;
name: string;
price: string | number;
rooms: string | number;
bathrooms: string | number;
image: string;
renter: string | undefined;
rented_till: string;
accumulated_rent: string;
rented: boolean;
user_is_host: boolean;
onClick(): void;
};
const ListingCard: React.FC<props> = (props) => {
const { name, price, rooms, bathrooms, image, rented, onClick } = props;
return (
<div className="w-full rounded-2xl cursor-pointer" onClick={onClick}>
<div
className="w-full h-48 rounded-lg mb-4 bg-gray-100 flex justify-end items-start p-2"
style={{
backgroundImage: `url(${image})`,
backgroundSize: "cover",
}}
>
{rented && (
<div>
<div className="px-2 py-1 bg-gray-200 text-gray-600 rounded uppercase text-xs tracking-wide font-semibold">
Unavailable
</div>
</div>
)}
</div>
<div className="flex items-center text-base font-light text-gray-600">
<p>
{rooms} Room{rooms > 1 ? "s" : ""}
</p>
<div className="w-1 h-1 bg-gray-500 rounded-full mx-2"></div>
<p>
{bathrooms} Bathroom{bathrooms > 1 ? "s" : ""}
</p>
</div>
<h3 className="text-gray-900 text-xl">{name}</h3>
<p className="text-gray-900 font-semibold">
{price} ZIL
<span className="text-gray-600 font-light"> / night</span>
</p>
</div>
);
};
export default ListingCard;
```
[/src/components/componentListingCard.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentListingCard.tsx)
<br/>
## Form Components
### Input
We create an Input component at [`/src/components/componentInput.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentInput.tsx). This works with state variables which will be created with the `useState` hook in its Parent Component. We accept the `name` for the input field. The input `type` and `unit` are also accepted as optional props.
```tsx
import React from "react";
type props = {
name: string;
unit?: string;
value?: string;
setValue(value: string): void;
type?: string;
};
const Input: React.FC<props> = (props) => {
const { name, unit = "", value = "", setValue, type = "text" } = props;
return (
<div className="">
<div className="flex justify-between items-center py-2 text-xs tracking-wide uppercase">
<h4 className="font-semibold text-gray-500">{name}</h4>
<p className="font-medium text-gray-400">{unit}</p>
</div>
<input
className="w-full mb-6 border-2 border-gray-300 focus:border-gray-900 rounded-button outline-none text-gray-900 lg:text-lg px-4 py-3"
placeholder={name}
type={"text"}
inputMode={type === "number" ? "decimal" : "text"}
min={type === "number" ? 1 : undefined}
value={value}
onChange={(e) => setValue(e.target.value)}
></input>
</div>
);
};
export default Input;
```
[/src/components/componentInput.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentInput.tsx)
<br/>
### CheckBox
We create a CheckBox component at [`/src/components/componentCheckBox.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentCheckBox.tsx). This component is used within the modals. The CreateAccount modal uses it for user role selection. It is also used for selecting amenities in the CreateListing and ManageListing Modals.
```tsx
import React from "react";
import Tick from "./componentTick";
type props = {
checked: boolean;
setChecked(checked: boolean): void;
children: any;
name: String;
};
const CheckBox: React.FC<props> = (props) => {
const { checked, setChecked, children, name } = props;
return (
<>
<div
className="flex justify-between items-center cursor-pointer mt-3"
onClick={() => setChecked(!checked)}
>
<div className="flex items-center">
{children}
<p className="text-lg text-gray-800 pl-4">{name}</p>
</div>
<div
className={`p-1 bg-gray-200 rounded-lg w-8 h-8 hover:scale-95 transform transition-all ${
checked ? "" : "hover:bg-gray-300"
}`}
>
<div
className={`w-full h-full rounded transition-colors text-transparent ${
checked ? "bg-gray-900 text-white" : ""
}`}
>
{checked && <Tick />}
</div>
</div>
</div>
</>
);
};
export default CheckBox;
```
[/src/components/componentCheckBox.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentCheckBox.tsx)
<br/>
### AmenitiesInput
We create an AmenitiesInput component at [`/src/components/componentAmenitiesInput.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentAmenitiesInput.tsx). It groups multiple checkboxes for collecting the amenities' availability in the CreateListing and ManageListing modals. We create this component to clean up the code.
```tsx
import React, { useEffect, useState } from "react";
import {
HvacIcon,
KitchenIcon,
LaundryIcon,
TvIcon,
WifiIcon,
} from "./componentListingIcons";
import CheckBox from "./componentCheckBox";
type props = {
wifi: boolean;
setWifi(wifi: boolean): void;
kitchen: boolean;
setKitchen(kitchen: boolean): void;
tv: boolean;
setTv(tv: boolean): void;
laundry: boolean;
setLaundry(laundry: boolean): void;
hvac: boolean;
setHvac(hvac: boolean): void;
};
const AmenitiesInput: React.FC<props> = (props) => {
const {
wifi,
setWifi,
kitchen,
setKitchen,
tv,
setTv,
laundry,
setLaundry,
hvac,
setHvac,
} = props;
const [selectAll, setSelectAll] = useState(true);
useEffect(() => {
setSelectAll(!(wifi || kitchen || tv || laundry || hvac));
}, [wifi, kitchen, tv, laundry, hvac]);
const setAll = (value: boolean) => {
setWifi(value);
setKitchen(value);
setTv(value);
setLaundry(value);
setHvac(value);
};
return (
<>
<div className="flex justify-between text-xs font-semibold text-gray-500 tracking-wide uppercase py-4">
<h4>Amenities</h4>
<p
className="font-medium text-gray-400 cursor-pointer hover:text-gray-500 transition-colors"
onClick={() => setAll(selectAll)}
>
{selectAll ? "Select All" : "Select None"}
</p>
</div>
<CheckBox name="WiFi" checked={wifi} setChecked={setWifi}>
<WifiIcon />
</CheckBox>
<CheckBox name="Kitchen" checked={kitchen} setChecked={setKitchen}>
<KitchenIcon />
</CheckBox>
<CheckBox name="Television" checked={tv} setChecked={setTv}>
<TvIcon />
</CheckBox>
<CheckBox name="Laundry" checked={laundry} setChecked={setLaundry}>
<LaundryIcon />
</CheckBox>
<CheckBox name="HVAC" checked={hvac} setChecked={setHvac}>
<HvacIcon />
</CheckBox>
</>
);
};
export default AmenitiesInput;
```
[/src/components/componentAmenitiesInput.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentAmenitiesInput.tsx)
<br/>
## SVG Components
### Tick
This Tick component at [`/src/components/componentTick.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentTick.tsx) is used to make the SVG easily available for the [CheckBox](#checkbox) component.
```tsx
import React from "react";
const Tick: React.FC = () => {
return (
<div className="w-full h-full grid place-items-center">
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={4}
d="M5 13l4 4L19 7"
/>
</svg>
</div>
);
};
export default Tick;
```
[/src/components/componentTick.tsx](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentTick.tsx)
<br/>
### Listing Icons
This [`/src/components/componentListingIcons.tsx`](https://github.com/Quinence/zilliqa-fullstack-app/blob/main/src/components/componentListingIcons.tsx) file contains several SVG components for use on the listing page as well as the listing management modals.
It includes icons for:
- `Wifi`
- `Kitchen`
- `TV`
- `Laundry`
- `HVAC`
- `Bedroom`
- `Bathroom`