mirror of
https://github.com/logos-storage/logos-storage-frontend.git
synced 2026-01-04 06:13:07 +00:00
ADD availabilities pages
This commit is contained in:
parent
a1af932c82
commit
07cf92153f
@ -1,3 +1,4 @@
|
|||||||
|
# please use localhost:8080 for codex_url for local development (without marketplace)
|
||||||
services:
|
services:
|
||||||
client:
|
client:
|
||||||
build:
|
build:
|
||||||
@ -7,6 +8,6 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "3000:80"
|
- "3000:80"
|
||||||
environment:
|
environment:
|
||||||
- codex_url=http://kubernetes.docker.internal:31942
|
- codex_url=http://kubernetes.docker.internal:31264
|
||||||
volumes:
|
volumes:
|
||||||
- ./deployment/nginx.template:/etc/nginx/templates/10-variables.conf.template:ro
|
- ./deployment/nginx.template:/etc/nginx/templates/10-variables.conf.template:ro
|
||||||
@ -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%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
71
frontend/src/components/layout/tabBarView/TabBarViewText.tsx
Normal file
71
frontend/src/components/layout/tabBarView/TabBarViewText.tsx
Normal 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;
|
||||||
|
}
|
||||||
|
`;
|
||||||
9
frontend/src/data/models/AvailabilityModel.ts
Normal file
9
frontend/src/data/models/AvailabilityModel.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
type AvailabilityModel = {
|
||||||
|
id: string;
|
||||||
|
size: string;
|
||||||
|
duration: string;
|
||||||
|
minPrice: string;
|
||||||
|
maxCollateral: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AvailabilityModel;
|
||||||
@ -4,7 +4,7 @@ import styled from "styled-components";
|
|||||||
import UploadedItemModel, {
|
import UploadedItemModel, {
|
||||||
UploadedItemStatus,
|
UploadedItemStatus,
|
||||||
} from "../../../../data/models/UploadedItemModel";
|
} from "../../../../data/models/UploadedItemModel";
|
||||||
import UploadedItemComponent from "../../../../components/uploadedItem/UploadedItemComponent";
|
import UploadedItemComponent from "../../../../components/UploadedItem/UploadedItemComponent";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
import { useDexyStore } from "../../../../store";
|
import { useDexyStore } from "../../../../store";
|
||||||
@ -64,6 +64,7 @@ function UploadTab() {
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
newCid = response.data;
|
newCid = response.data;
|
||||||
|
getDatas();
|
||||||
});
|
});
|
||||||
console.log("filesCopy failed");
|
console.log("filesCopy failed");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,22 +1,30 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import TabBarView from "../../components/layout/tabBarView/TabBarView";
|
import TabBarViewText from "../../components/layout/tabBarView/TabBarViewText";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { MdFileUpload, MdFileDownload } from "react-icons/md";
|
import { MdFileUpload, MdFileDownload } from "react-icons/md";
|
||||||
import UploadTab from "./tabs/status/StatusTab";
|
import UploadTab from "./tabs/Rosc/StatusTab";
|
||||||
import DownloadTab from "./tabs/create/CreateTab";
|
import DownloadTab from "./tabs/Rosc/CreateTab";
|
||||||
import StatusTab from "./tabs/status/StatusTab";
|
import StatusTab from "./tabs/Rosc/StatusTab";
|
||||||
import CreateTab from "./tabs/create/CreateTab";
|
import CreateTab from "./tabs/Rosc/CreateTab";
|
||||||
|
import OfferStorage from "./tabs/Availability/OfferStorage";
|
||||||
|
import AvailabilitiesTab from "./tabs/Availability/Availability";
|
||||||
|
|
||||||
function MarketplacePage() {
|
function MarketplacePage() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TabBarView tabIcons={[MdFileUpload, MdFileDownload, MdFileUpload, MdFileDownload]}>
|
<TabBarViewText tabText={["ROSC Status", "ROSC create", "Availabilities", "Create Availability"]}>
|
||||||
<StatusTab />
|
<StatusTab />
|
||||||
<TabBarViewPage>
|
<TabBarViewPage>
|
||||||
<CreateTab />
|
<CreateTab />
|
||||||
</TabBarViewPage>
|
</TabBarViewPage>
|
||||||
</TabBarView>
|
<TabBarViewPage>
|
||||||
|
<AvailabilitiesTab />
|
||||||
|
</TabBarViewPage>
|
||||||
|
<TabBarViewPage>
|
||||||
|
<OfferStorage />
|
||||||
|
</TabBarViewPage>
|
||||||
|
</TabBarViewText>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -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%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -2,6 +2,7 @@ import { create } from "zustand";
|
|||||||
import { persist } from "zustand/middleware";
|
import { persist } from "zustand/middleware";
|
||||||
import UploadedItemModel from "./data/models/UploadedItemModel";
|
import UploadedItemModel from "./data/models/UploadedItemModel";
|
||||||
import RequestForStorageContractModel from "./data/models/RequestForStorageContractModel";
|
import RequestForStorageContractModel from "./data/models/RequestForStorageContractModel";
|
||||||
|
import AvailabilityModel from "./data/models/AvailabilityModel";
|
||||||
interface NodeInfo {
|
interface NodeInfo {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
nodeToConnectTo: string | null;
|
nodeToConnectTo: string | null;
|
||||||
@ -16,6 +17,8 @@ interface DexyState {
|
|||||||
setUploads: (uploads: UploadedItemModel[]) => void;
|
setUploads: (uploads: UploadedItemModel[]) => void;
|
||||||
storageRequests: RequestForStorageContractModel[];
|
storageRequests: RequestForStorageContractModel[];
|
||||||
setStorageRequests: (storageRequests: RequestForStorageContractModel[]) => void;
|
setStorageRequests: (storageRequests: RequestForStorageContractModel[]) => void;
|
||||||
|
storageOffers: AvailabilityModel[];
|
||||||
|
setStorageOffers: (storageOffers: AvailabilityModel[]) => void;
|
||||||
ftdCid: string;
|
ftdCid: string;
|
||||||
setFtdCid: (cid: string) => void;
|
setFtdCid: (cid: string) => void;
|
||||||
nodeInfo: NodeInfo;
|
nodeInfo: NodeInfo;
|
||||||
@ -29,6 +32,8 @@ export const useDexyStore = create<DexyState>()(
|
|||||||
setUploads: (uploads) => set({ uploads }),
|
setUploads: (uploads) => set({ uploads }),
|
||||||
storageRequests: [],
|
storageRequests: [],
|
||||||
setStorageRequests: (storageRequests) => set({ storageRequests }),
|
setStorageRequests: (storageRequests) => set({ storageRequests }),
|
||||||
|
storageOffers: [],
|
||||||
|
setStorageOffers: (storageOffers) => set({ storageOffers }),
|
||||||
ftdCid: "",
|
ftdCid: "",
|
||||||
setFtdCid: (cid) => set({ ftdCid: cid }),
|
setFtdCid: (cid) => set({ ftdCid: cid }),
|
||||||
nodeInfo: {
|
nodeInfo: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user