From 07cf92153f5cc69d2e4276f85e223276a64b7af7 Mon Sep 17 00:00:00 2001
From: Shaun Orssaud <72015533+Shorssaud@users.noreply.github.com>
Date: Wed, 22 Nov 2023 13:59:52 +0900
Subject: [PATCH] ADD availabilities pages
---
docker-compose.yml | 3 +-
.../AvailableComponent/AvailableComponent.tsx | 97 ++++++++++++
.../layout/tabBarView/TabBarViewText.tsx | 71 +++++++++
frontend/src/data/models/AvailabilityModel.ts | 9 ++
.../src/pages/data/tabs/upload/UploadTab.tsx | 3 +-
.../src/pages/marketplace/Marketplace.tsx | 22 ++-
.../tabs/Availability/Availability.tsx | 72 +++++++++
.../tabs/Availability/OfferStorage.tsx | 142 ++++++++++++++++++
.../tabs/{create => Rosc}/CreateTab.tsx | 0
.../tabs/{status => Rosc}/StatusTab.tsx | 0
frontend/src/store.ts | 5 +
11 files changed, 415 insertions(+), 9 deletions(-)
create mode 100644 frontend/src/components/AvailableComponent/AvailableComponent.tsx
create mode 100644 frontend/src/components/layout/tabBarView/TabBarViewText.tsx
create mode 100644 frontend/src/data/models/AvailabilityModel.ts
create mode 100644 frontend/src/pages/marketplace/tabs/Availability/Availability.tsx
create mode 100644 frontend/src/pages/marketplace/tabs/Availability/OfferStorage.tsx
rename frontend/src/pages/marketplace/tabs/{create => Rosc}/CreateTab.tsx (100%)
rename frontend/src/pages/marketplace/tabs/{status => Rosc}/StatusTab.tsx (100%)
diff --git a/docker-compose.yml b/docker-compose.yml
index a66f994..1a9c402 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,3 +1,4 @@
+# please use localhost:8080 for codex_url for local development (without marketplace)
services:
client:
build:
@@ -7,6 +8,6 @@ services:
ports:
- "3000:80"
environment:
- - codex_url=http://kubernetes.docker.internal:31942
+ - codex_url=http://kubernetes.docker.internal:31264
volumes:
- ./deployment/nginx.template:/etc/nginx/templates/10-variables.conf.template:ro
\ No newline at end of file
diff --git a/frontend/src/components/AvailableComponent/AvailableComponent.tsx b/frontend/src/components/AvailableComponent/AvailableComponent.tsx
new file mode 100644
index 0000000..03ccce6
--- /dev/null
+++ b/frontend/src/components/AvailableComponent/AvailableComponent.tsx
@@ -0,0 +1,97 @@
+import React from "react";
+import styled from "styled-components";
+
+import { CircularProgress } from "@mui/material";
+import { MdCheck, MdError } from "react-icons/md";
+import AvailabilityModel from "../../data/models/AvailabilityModel";
+import constants from "../../util/Constants";
+
+function AvailableComponent(props: { item: AvailabilityModel }) {
+ return (
+
+
+
+ ID:
+ {props.item.id}
+
+
+ Size:
+ {props.item.size}
+
+
+
+
+ Duration:
+ {props.item.duration}
+
+
+ Min Price:
+ {props.item.minPrice}
+
+
+
+
+ Max Collateral:
+ {props.item.maxCollateral}
+
+
+
+ );
+}
+
+export default AvailableComponent;
+
+const AvailableComponentWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ background-color: ${constants.surfaceColor};
+ border-radius: 8px;
+ padding: 10px;
+ width: 80%;
+ margin-top: 20px;
+
+ div {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ margin: 5px;
+ }
+
+ div p:nth-child(1) {
+ text-align: start;
+ }
+
+ div p:nth-child(2) {
+ text-align: end;
+ }
+
+ p {
+ flex: 1;
+ font-size: 1rem;
+ text-align: start;
+ margin: 5px;
+ }
+
+ p span {
+ font-weight: bold;
+ }
+
+ #cid {
+ flex: 2;
+ }
+
+ @media (max-width: 1180px) {
+ width: 85%;
+ }
+
+ @media (max-width: 768px) {
+ width: 90%;
+ }
+
+ @media (max-width: 450px) {
+ width: 95%;
+ }
+`;
diff --git a/frontend/src/components/layout/tabBarView/TabBarViewText.tsx b/frontend/src/components/layout/tabBarView/TabBarViewText.tsx
new file mode 100644
index 0000000..1f69c1f
--- /dev/null
+++ b/frontend/src/components/layout/tabBarView/TabBarViewText.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+import styled from "styled-components";
+
+function TabBarViewText(props: {
+ tabText: String[];
+ children: React.ReactNode[];
+}) {
+ const [activeTab, setActiveTab] = React.useState(0);
+
+ return (
+
+
+ {props.tabText.map((text, index) => (
+
+ ))}
+
+ {props.children[activeTab]}
+
+ );
+}
+
+export default TabBarViewText;
+
+const TabBarViewTextWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: start;
+ padding: 0;
+ margin: 0;
+ height: 100%;
+
+ #tab-wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-evenly;
+ list-style: none;
+ padding: 0;
+ margin-bottom: 10px;
+ width: 100%;
+ }
+
+ #tab-wrapper button {
+ flex: 1;
+ background-color: #141414;
+ color: #9e9e9e;
+ border: none;
+ padding: 24px;
+ cursor: pointer;
+ font-size: 1rem;
+ }
+
+ #tab-view {
+ height: 100%;
+ width: 100%;
+ }
+
+ @media (min-width: 768px) {
+ height: 100vh - 300px !important;
+ }
+`;
diff --git a/frontend/src/data/models/AvailabilityModel.ts b/frontend/src/data/models/AvailabilityModel.ts
new file mode 100644
index 0000000..84a2b94
--- /dev/null
+++ b/frontend/src/data/models/AvailabilityModel.ts
@@ -0,0 +1,9 @@
+type AvailabilityModel = {
+ id: string;
+ size: string;
+ duration: string;
+ minPrice: string;
+ maxCollateral: string;
+};
+
+export default AvailabilityModel;
\ No newline at end of file
diff --git a/frontend/src/pages/data/tabs/upload/UploadTab.tsx b/frontend/src/pages/data/tabs/upload/UploadTab.tsx
index 4be4247..44ba889 100644
--- a/frontend/src/pages/data/tabs/upload/UploadTab.tsx
+++ b/frontend/src/pages/data/tabs/upload/UploadTab.tsx
@@ -4,7 +4,7 @@ import styled from "styled-components";
import UploadedItemModel, {
UploadedItemStatus,
} from "../../../../data/models/UploadedItemModel";
-import UploadedItemComponent from "../../../../components/uploadedItem/UploadedItemComponent";
+import UploadedItemComponent from "../../../../components/UploadedItem/UploadedItemComponent";
import axios from "axios";
import { useDexyStore } from "../../../../store";
@@ -64,6 +64,7 @@ function UploadTab() {
})
.then((response) => {
newCid = response.data;
+ getDatas();
});
console.log("filesCopy failed");
} catch (error) {
diff --git a/frontend/src/pages/marketplace/Marketplace.tsx b/frontend/src/pages/marketplace/Marketplace.tsx
index 96e0bfc..b995c5a 100644
--- a/frontend/src/pages/marketplace/Marketplace.tsx
+++ b/frontend/src/pages/marketplace/Marketplace.tsx
@@ -1,22 +1,30 @@
import React from "react";
-import TabBarView from "../../components/layout/tabBarView/TabBarView";
+import TabBarViewText from "../../components/layout/tabBarView/TabBarViewText";
import styled from "styled-components";
import { MdFileUpload, MdFileDownload } from "react-icons/md";
-import UploadTab from "./tabs/status/StatusTab";
-import DownloadTab from "./tabs/create/CreateTab";
-import StatusTab from "./tabs/status/StatusTab";
-import CreateTab from "./tabs/create/CreateTab";
+import UploadTab from "./tabs/Rosc/StatusTab";
+import DownloadTab from "./tabs/Rosc/CreateTab";
+import StatusTab from "./tabs/Rosc/StatusTab";
+import CreateTab from "./tabs/Rosc/CreateTab";
+import OfferStorage from "./tabs/Availability/OfferStorage";
+import AvailabilitiesTab from "./tabs/Availability/Availability";
function MarketplacePage() {
return (
);
}
diff --git a/frontend/src/pages/marketplace/tabs/Availability/Availability.tsx b/frontend/src/pages/marketplace/tabs/Availability/Availability.tsx
new file mode 100644
index 0000000..8b5902a
--- /dev/null
+++ b/frontend/src/pages/marketplace/tabs/Availability/Availability.tsx
@@ -0,0 +1,72 @@
+import { useEffect, useRef, useState } from "react";
+import styled from "styled-components";
+
+import { useDexyStore } from "../../../../store";
+import AvailableComponent from "../../../../components/AvailableComponent/AvailableComponent";
+
+function AvailabilitiesTab() {
+ const { storageOffers, setStorageOffers, nodeInfo } = useDexyStore();
+ const [isLoading, setIsLoading] = useState(false);
+
+ useEffect(() => {
+ setIsLoading(true);
+ // Fetch purchase IDs
+ fetch(`/api/codex/v1/sales/availability`, {
+ headers: {
+ Authorization: nodeInfo.auth ? "Basic " + btoa(nodeInfo.auth) : "",
+ },
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ setStorageOffers(data);
+ setIsLoading(false);
+ })
+ .catch((error) => {
+ console.error("Error fetching purchase IDs:", error);
+ setIsLoading(false);
+ });
+ }, []);
+
+ return (
+
+ 0 ? "60vh" : "0%",
+ }}
+ >
+ {isLoading ? (
+
Loading...
+ ) : (
+ storageOffers.map((item) => (
+
+ ))
+ )}
+
+
+ );
+}
+
+export default AvailabilitiesTab;
+
+const AvailabilitiesTabWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ width: 100%;
+ padding: 16px;
+
+ #request-wrap {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: start;
+ width: 100%;
+ overflow-y: scroll;
+ margin-top: 16px;
+ }
+`;
diff --git a/frontend/src/pages/marketplace/tabs/Availability/OfferStorage.tsx b/frontend/src/pages/marketplace/tabs/Availability/OfferStorage.tsx
new file mode 100644
index 0000000..b5032c3
--- /dev/null
+++ b/frontend/src/pages/marketplace/tabs/Availability/OfferStorage.tsx
@@ -0,0 +1,142 @@
+import { useState } from "react";
+import constants from "../../../../util/Constants";
+import styled from "styled-components";
+import { useDexyStore } from "../../../../store";
+
+function OfferStorage() {
+ const { ftdCid, setFtdCid, nodeInfo } = useDexyStore();
+
+ const [size, setSize,] = useState("file");
+ const [duration, setDuration,] = useState("file");
+ const [minPrice, setMinPrice,] = useState("file");
+ const [maxCollateral, setMaxCollateral,] = useState("file");
+
+
+ function upload(cid: string) {
+ fetch(
+ `/api/codex/v1/sales/availability`,
+ {
+ method: 'POST',
+ headers:
+ (nodeInfo.auth !== null && {
+ Authorization:
+ (nodeInfo.auth && "Basic " + btoa(nodeInfo.auth)) || "",
+ }) ||
+ {},
+ body: JSON.stringify({
+ size: size,
+ duration: duration,
+ minPrice: minPrice,
+ maxCollateral: maxCollateral
+ })
+ }
+ )
+ // create a popup in the browser to show if the upload was successful
+ .then((response) => {
+ if (response.status === 200) {
+ alert("Upload successful!");
+ } else {
+ alert("Upload failed!");
+ }
+ })
+ }
+
+ return (
+
+ {
+ setFtdCid(e.target.value);
+ }}
+ value={ftdCid}
+ />
+
+ setSize(e.target.value)}
+ />
+
+ setDuration(e.target.value)}
+ />
+
+ setMinPrice(e.target.value)}
+ />
+
+ setMaxCollateral(e.target.value)}
+ />
+
+
+ );
+}
+
+export default OfferStorage;
+
+const OfferStorageWrapper = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ width: 75%;
+
+ input {
+ flex: 3;
+ height: 60px;
+ padding: 10px 20px;
+ border: none;
+ background-color: ${constants.surfaceColor};
+ color: ${constants.onSurfaceColor};
+ width: 100%;
+ }
+
+ input:focus {
+ outline: none;
+ border: 2px solid ${constants.primaryColor};
+ }
+
+ input:nth-child(1) {
+ border-top-left-radius: 8px;
+ border-bottom-left-radius: 8px;
+ }
+
+ #divider {
+ width: 2.5px;
+ height: 60px;
+ background-color: #555555;
+ }
+
+ button {
+ flex: 2;
+ height: 60px;
+ border: none;
+ background-color: ${constants.primaryColor};
+ color: ${constants.onPrimaryColor};
+ font-size: 1rem;
+ cursor: pointer;
+ border-top-right-radius: 8px;
+ border-bottom-right-radius: 8px;
+ width: 100%;
+ }
+
+ @media (max-width: 1180px) {
+ width: 80%;
+ }
+
+ @media (max-width: 768px) {
+ width: 85%;
+ }
+
+ @media (max-width: 450px) {
+ width: 90%;
+ }
+`;
diff --git a/frontend/src/pages/marketplace/tabs/create/CreateTab.tsx b/frontend/src/pages/marketplace/tabs/Rosc/CreateTab.tsx
similarity index 100%
rename from frontend/src/pages/marketplace/tabs/create/CreateTab.tsx
rename to frontend/src/pages/marketplace/tabs/Rosc/CreateTab.tsx
diff --git a/frontend/src/pages/marketplace/tabs/status/StatusTab.tsx b/frontend/src/pages/marketplace/tabs/Rosc/StatusTab.tsx
similarity index 100%
rename from frontend/src/pages/marketplace/tabs/status/StatusTab.tsx
rename to frontend/src/pages/marketplace/tabs/Rosc/StatusTab.tsx
diff --git a/frontend/src/store.ts b/frontend/src/store.ts
index b01be82..a63a00e 100644
--- a/frontend/src/store.ts
+++ b/frontend/src/store.ts
@@ -2,6 +2,7 @@ import { create } from "zustand";
import { persist } from "zustand/middleware";
import UploadedItemModel from "./data/models/UploadedItemModel";
import RequestForStorageContractModel from "./data/models/RequestForStorageContractModel";
+import AvailabilityModel from "./data/models/AvailabilityModel";
interface NodeInfo {
baseUrl: string;
nodeToConnectTo: string | null;
@@ -16,6 +17,8 @@ interface DexyState {
setUploads: (uploads: UploadedItemModel[]) => void;
storageRequests: RequestForStorageContractModel[];
setStorageRequests: (storageRequests: RequestForStorageContractModel[]) => void;
+ storageOffers: AvailabilityModel[];
+ setStorageOffers: (storageOffers: AvailabilityModel[]) => void;
ftdCid: string;
setFtdCid: (cid: string) => void;
nodeInfo: NodeInfo;
@@ -29,6 +32,8 @@ export const useDexyStore = create()(
setUploads: (uploads) => set({ uploads }),
storageRequests: [],
setStorageRequests: (storageRequests) => set({ storageRequests }),
+ storageOffers: [],
+ setStorageOffers: (storageOffers) => set({ storageOffers }),
ftdCid: "",
setFtdCid: (cid) => set({ ftdCid: cid }),
nodeInfo: {