ADD availabilities pages

This commit is contained in:
Shaun Orssaud 2023-11-22 13:59:52 +09:00
parent a1af932c82
commit 07cf92153f
11 changed files with 415 additions and 9 deletions

View File

@ -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

View File

@ -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 (
<AvailableComponentWrapper>
<div>
<p>
<span>ID: </span>
{props.item.id}
</p>
<p>
<span>Size: </span>
{props.item.size}
</p>
</div>
<div>
<p>
<span>Duration: </span>
{props.item.duration}
</p>
<p>
<span>Min Price: </span>
{props.item.minPrice}
</p>
</div>
<div>
<p>
<span>Max Collateral: </span>
{props.item.maxCollateral}
</p>
</div>
</AvailableComponentWrapper>
);
}
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%;
}
`;

View File

@ -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 (
<TabBarViewTextWrapper>
<div id="tab-wrapper">
{props.tabText.map((text, index) => (
<button
style={{
color: activeTab === index ? "#6f11db" : "#9e9e9e",
borderBottom: activeTab === index ? "2px solid #6f11db" : "none",
}}
onClick={() => setActiveTab(index)}
key={index}
>
{text}
</button>
))}
</div>
<div id="tab-view">{props.children[activeTab]}</div>
</TabBarViewTextWrapper>
);
}
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;
}
`;

View File

@ -0,0 +1,9 @@
type AvailabilityModel = {
id: string;
size: string;
duration: string;
minPrice: string;
maxCollateral: string;
};
export default AvailabilityModel;

View File

@ -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) {

View File

@ -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 (
<div>
<TabBarView tabIcons={[MdFileUpload, MdFileDownload, MdFileUpload, MdFileDownload]}>
<TabBarViewText tabText={["ROSC Status", "ROSC create", "Availabilities", "Create Availability"]}>
<StatusTab />
<TabBarViewPage>
<CreateTab />
</TabBarViewPage>
</TabBarView>
<TabBarViewPage>
<AvailabilitiesTab />
</TabBarViewPage>
<TabBarViewPage>
<OfferStorage />
</TabBarViewPage>
</TabBarViewText>
</div>
);
}

View File

@ -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 (
<AvailabilitiesTabWrapper>
<div
id="request-wrap"
style={{
maxHeight: storageOffers.length > 0 ? "60vh" : "0%",
}}
>
{isLoading ? (
<p>Loading...</p>
) : (
storageOffers.map((item) => (
<AvailableComponent
item={item}
/>
))
)}
</div>
</AvailabilitiesTabWrapper>
);
}
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;
}
`;

View File

@ -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 (
<OfferStorageWrapper>
<input
type="text"
placeholder="CID"
onChange={(e) => {
setFtdCid(e.target.value);
}}
value={ftdCid}
/>
<div id="divider"></div>
<input
type="text"
placeholder="Size"
onChange={(e) => setSize(e.target.value)}
/>
<div id="divider"></div>
<input
type="text"
placeholder="Duration"
onChange={(e) => setDuration(e.target.value)}
/>
<div id="divider"></div>
<input
type="text"
placeholder="MinPrice"
onChange={(e) => setMinPrice(e.target.value)}
/>
<div id="divider"></div>
<input
type="text"
placeholder="MaxCollateral"
onChange={(e) => setMaxCollateral(e.target.value)}
/>
<button onClick={() => upload(ftdCid)}>Download</button>
</OfferStorageWrapper>
);
}
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%;
}
`;

View File

@ -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<DexyState>()(
setUploads: (uploads) => set({ uploads }),
storageRequests: [],
setStorageRequests: (storageRequests) => set({ storageRequests }),
storageOffers: [],
setStorageOffers: (storageOffers) => set({ storageOffers }),
ftdCid: "",
setFtdCid: (cid) => set({ ftdCid: cid }),
nodeInfo: {