diff --git a/sitemap.xml b/sitemap.xml
index 0f3a66a..171b043 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -11,4 +11,14 @@
2024-08-30
1.00
+
+ https://dapp.ekoketoken.com/marketplace
+ 2024-08-30
+ 1.00
+
+
+ https://dapp.ekoketoken.com/timeline
+ 2024-08-30
+ 1.00
+
diff --git a/src/js/components/App/Routes.tsx b/src/js/components/App/Routes.tsx
index 4f3a023..f841985 100644
--- a/src/js/components/App/Routes.tsx
+++ b/src/js/components/App/Routes.tsx
@@ -7,6 +7,7 @@ import Timeline from './pages/Timeline';
import UserStories from './pages/UserStories';
import SeoEngine from '../SeoEngine';
import Marketplace from './pages/Marketplace';
+import ContractPage from './pages/Marketplace/pages/Contract';
const AppRouter = () => (
<>
@@ -18,6 +19,10 @@ const AppRouter = () => (
path={Route.url(Route.MARKETPLACE)}
element={}
/>
+ }
+ />
} />
{
+ const { id } = useParams<{ id: string }>();
+ const [contract, setContract] = React.useState();
+
+ React.useEffect(() => {
+ const assocContract = mockedContracts().find(
+ (contract) => contract.id.toString() === id,
+ );
+ if (assocContract) {
+ setContract(assocContract);
+ }
+ }, [id]);
+
+ if (!contract) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ContractPage;
diff --git a/src/js/components/App/pages/Marketplace/pages/Contract/RealEstateCard.tsx b/src/js/components/App/pages/Marketplace/pages/Contract/RealEstateCard.tsx
new file mode 100644
index 0000000..ad148e0
--- /dev/null
+++ b/src/js/components/App/pages/Marketplace/pages/Contract/RealEstateCard.tsx
@@ -0,0 +1,68 @@
+import * as React from 'react';
+import * as Icon from 'react-feather';
+
+import { Contract } from '../../../../../../data/contract';
+import Container from '../../../../../reusable/Container';
+import Heading from '../../../../../reusable/Heading';
+import Paragraph from '../../../../../reusable/Paragraph';
+import ProgressBar from '../../../../../reusable/ProgressBar';
+
+const INSTALLMENT_VALUE = 100;
+
+interface Props {
+ contract: Contract;
+}
+
+const RealEstateCard = ({ contract }: Props) => {
+ const installments = contract.realEstate.price / INSTALLMENT_VALUE;
+
+ return (
+
+
+
+
+
+
+
+ {contract.realEstate.name}
+
+
+ {contract.realEstate.price.toLocaleString('en-US', {
+ style: 'currency',
+ currency: 'USD',
+ })}
+
+
+
+ {contract.realEstate.address}
+
+
+
+ {Math.floor(Math.random() * 6) + 1} Rooms -{' '}
+ {Math.floor(Math.random() * 2) + 1} Bathrooms
+
+
+
+
+ Mortgage payment progress
+
+
+ {contract.realEstate.description}
+
+
+ );
+};
+
+export default RealEstateCard;
diff --git a/src/js/components/App/pages/Marketplace/pages/Contract/TokensList.tsx b/src/js/components/App/pages/Marketplace/pages/Contract/TokensList.tsx
new file mode 100644
index 0000000..cb8e19d
--- /dev/null
+++ b/src/js/components/App/pages/Marketplace/pages/Contract/TokensList.tsx
@@ -0,0 +1,33 @@
+import * as React from 'react';
+
+import { Contract } from '../../../../../../data/contract';
+import Container from '../../../../../reusable/Container';
+import Heading from '../../../../../reusable/Heading';
+import TokenItem from './TokensList/TokenItem';
+
+interface Props {
+ contract: Contract;
+}
+
+const INSTALLMENT_VALUE = 100;
+
+const TokensList = ({ contract }: Props) => {
+ const tokenValue = contract.realEstate.price / INSTALLMENT_VALUE;
+ const tokens = Array.from({ length: 10 }, (_, i) => ({
+ id: i,
+ value: tokenValue,
+ }));
+
+ return (
+
+ Tokens for sale
+
+ {tokens.map((token) => (
+
+ ))}
+
+
+ );
+};
+
+export default TokensList;
diff --git a/src/js/components/App/pages/Marketplace/pages/Contract/TokensList/TokenItem.tsx b/src/js/components/App/pages/Marketplace/pages/Contract/TokensList/TokenItem.tsx
new file mode 100644
index 0000000..a65adfe
--- /dev/null
+++ b/src/js/components/App/pages/Marketplace/pages/Contract/TokensList/TokenItem.tsx
@@ -0,0 +1,33 @@
+import * as React from 'react';
+import * as Icon from 'react-feather';
+
+import Container from '../../../../../../reusable/Container';
+import Heading from '../../../../../../reusable/Heading';
+import Button from '../../../../../../reusable/Button';
+
+interface Props {
+ id: number;
+ value: number;
+}
+
+const TokenItem = ({ id, value }: Props) => (
+
+
+
+ Token #{id}
+
+
+ {value.toLocaleString('en-US', {
+ style: 'currency',
+ currency: 'USD',
+ })}
+
+
+
+ Buy Token
+
+
+
+);
+
+export default TokenItem;
diff --git a/src/js/components/App/pages/Timeline/TimelineSvg.tsx b/src/js/components/App/pages/Timeline/TimelineSvg.tsx
index 9200be5..1c7f3ca 100644
--- a/src/js/components/App/pages/Timeline/TimelineSvg.tsx
+++ b/src/js/components/App/pages/Timeline/TimelineSvg.tsx
@@ -37,163 +37,163 @@ const Timeline = () => {
>
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
{
height={899.999994}
fillOpacity={1}
/>
-
+
{
fillRule="nonzero"
/>
-
+
{
fillRule="nonzero"
/>
-
+
{
fillOpacity={1}
fillRule="nonzero"
/>
-
+
{
fillOpacity={1}
fillRule="nonzero"
/>
-
+
{
fillOpacity={1}
fillRule="nonzero"
/>
-
+
{
fillOpacity={1}
fillRule="nonzero"
/>
-
+
{
fillOpacity={1}
fillRule="nonzero"
/>
-
-
+
+
{
-
-
+
+
{
-
-
+
+
{
-
-
+
+
{
-
-
+
+
{
-
-
+
+
{
-
+
{
-
+
{
fillRule="nonzero"
/>
-
+
{
fillOpacity={1}
fillRule="evenodd"
/>
-
+
{
fillRule="evenodd"
/>
-
+
{
fillOpacity={1}
fillRule="evenodd"
/>
-
+
{
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -2078,120 +2078,198 @@ const Timeline = () => {
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -5759,7 +5837,7 @@ const Timeline = () => {
fillOpacity={1}
fillRule="evenodd"
/>
-
+
{
fillRule="evenodd"
/>
-
+
) => (
);
+const H1L = (props: React.HTMLProps) => (
+
+ {props.children}
+
+);
+
const H2 = (props: React.HTMLProps) => (
) => (
export default {
H1,
+ H1L,
H2,
H3,
H4,
diff --git a/src/js/components/reusable/ProgressBar.tsx b/src/js/components/reusable/ProgressBar.tsx
new file mode 100644
index 0000000..7720556
--- /dev/null
+++ b/src/js/components/reusable/ProgressBar.tsx
@@ -0,0 +1,33 @@
+import * as React from 'react';
+
+interface Props {
+ progress: number;
+ max: number;
+ percentage?: boolean;
+}
+
+const ProgressBar = (props: Props) => {
+ const percentage = Math.round((props.progress * 100) / props.max);
+ let label = `${props.progress}/${props.max}`;
+ if (props.percentage) {
+ label = `${percentage.toString()}%`;
+ }
+
+ const className = `${
+ props.progress > 0 ? 'bg-brand' : ''
+ } text-lg font-medium text-blue-100 text-center p-0.5 leading-none rounded-full`;
+
+ const fillerStyles = {
+ width: `${percentage}%`,
+ };
+
+ return (
+
+ );
+};
+
+export default ProgressBar;