forked from alefmanvladimir/BigFiles
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request alefmanvladimir#23 from d0rich/beautify-frontend-1
Beautify frontend
- Loading branch information
Showing
22 changed files
with
531 additions
and
236 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 42 additions & 32 deletions
74
ton-drive-frontend/src/entities/file/ui/FilesListItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,50 @@ | ||
import type {TonStorageFile} from "../model/TonStorageFile" | ||
import FileSize from "./FileSize" | ||
import FileDate from "./FileDate" | ||
import FileTypeIcon from "./FileTypeIcon" | ||
import type { TonStorageFile } from "../model/TonStorageFile"; | ||
import FileSize from "./FileSize"; | ||
import FileDate from "./FileDate"; | ||
import FileTypeIcon from "./FileTypeIcon"; | ||
import ContractLink from "../../../shared/ui/ContractLink"; | ||
|
||
export interface FilesListItemProps { | ||
file: TonStorageFile | ||
className?: string | ||
actions?: JSX.Element | ||
file: TonStorageFile; | ||
className?: string; | ||
actions?: JSX.Element; | ||
} | ||
|
||
export default function FilesListItem({file, className, actions}: FilesListItemProps) { | ||
return ( | ||
<li className={`card card-compact flex-row items-center gap-2 bg-base-300 p-3 ${className ?? ''}`}> | ||
export default function FilesListItem({ file, className, actions }: FilesListItemProps) { | ||
return ( | ||
<li className={`card card-compact bg-base-300 p-3 ${className ?? ""}`}> | ||
<div className="font-bold text-md"> | ||
{file.name} | ||
<div className="badge badge-neutral ml-1">{file.extension}</div> | ||
</div> | ||
<div className="flex flex-col sm:flex-row gap-2 "> | ||
<div className="flex flex-col sm:flex-row sm:items-center gap-2 text-ellipsis overflow-hidden"> | ||
<div className="flex items-center gap-2 sm:w-1/4"> | ||
<div> | ||
<FileTypeIcon extension={file.extension}/> | ||
<FileTypeIcon extension={file.extension} /> | ||
</div> | ||
<div className="text-ellipsis overflow-hidden"> | ||
<div className="card-title"> | ||
{file.name} | ||
<div className="badge badge-neutral">{file.extension}</div> | ||
</div> | ||
<div className="text-accent-content text-sm"><FileSize size={file.size}/> | <FileDate date={file.date}/> | ||
</div> | ||
<span className="text-accent-content text-sm">{file.bagId}</span> | ||
<div> | ||
<span className="text-accent-content text-sm"> | ||
Storage Contract: { | ||
file.storageContractInfo.address ? file.storageContractInfo.address?.toString() : <span className={'text-error-content text-sm'}>Not ready</span> | ||
} | ||
</span> | ||
</div> | ||
<div className="sm:flex sm:flex-col"> | ||
<div className="text-accent-content text-xs"> | ||
<FileSize size={file.size} /> | <FileDate date={file.date} /> | ||
</div> | ||
</div> | ||
{/* Actions */} | ||
<div className="ml-auto"> | ||
{actions} | ||
</div> | ||
</li> | ||
) | ||
</div> | ||
<table className="table table-xs"> | ||
<tbody> | ||
<tr> | ||
<th>Bag ID</th> | ||
<td>{file.bagId}</td> | ||
</tr> | ||
<tr> | ||
<th>Contract</th> | ||
<td>{file.storageContractInfo.address ? <ContractLink address={file.storageContractInfo.address?.toString()} /> : <span className={"text-error-content text-sm"}>Not ready</span>}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
{/* Actions */} | ||
<div className="ml-auto">{actions}</div> | ||
</div> | ||
</li> | ||
); | ||
} |
38 changes: 38 additions & 0 deletions
38
ton-drive-frontend/src/features/drive/hook/useCollectionInfo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import {CollectionInfo} from "../../../services/FilesService"; | ||
import {useEffect, useState} from "react"; | ||
import {useMyCollection} from "./useMyCollection"; | ||
import { useRealtimeRemoteState } from "../../../shared/hooks/useRealtimeRemoteState"; | ||
|
||
export function useCollectionInfo(): CollectionInfo | null { | ||
const [info, setInfo] = useState<CollectionInfo | null>(null) | ||
const myCollection = useMyCollection() | ||
|
||
useEffect(() => { | ||
if (myCollection == null) { | ||
return; | ||
} | ||
myCollection | ||
.info() | ||
.then(setInfo) | ||
}, [myCollection]) | ||
|
||
return info | ||
} | ||
|
||
export function useRealtimeCollectionInfo(): CollectionInfo | null { | ||
const myCollection = useMyCollection() | ||
return useRealtimeRemoteState({ | ||
fetchFn: async () => { | ||
if (myCollection == null) { | ||
return null; | ||
} | ||
return myCollection.info() | ||
}, | ||
isEqualFn: (oldData, newData) => { | ||
const isAddressEqual = oldData?.address.toString() === newData?.address.toString() | ||
const isBalanceEqual = oldData?.balance === newData?.balance | ||
return isAddressEqual && isBalanceEqual | ||
}, | ||
deps: [myCollection] | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
ton-drive-frontend/src/features/drive/ui/RequireUserDrive.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { useRealtimeCollectionInfo } from "../hook/useCollectionInfo"; | ||
|
||
export interface RequireUserDriveProps { | ||
children?: JSX.Element | JSX.Element[]; | ||
fallback?: JSX.Element; | ||
} | ||
|
||
export default function RequireUserDrive({ children, fallback = <></> }: RequireUserDriveProps) { | ||
const userDrive = useRealtimeCollectionInfo(); | ||
|
||
const showChildren = userDrive != null && userDrive.balance > 0; | ||
|
||
return (<> | ||
{showChildren ? children : fallback} | ||
</>) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { Sender, TonClient } from "ton"; | ||
import {Address, Cell} from "ton-core"; | ||
import tonDrive, {storageProviderAddress} from "../../../services/FilesService"; | ||
|
||
export interface FileUploadOptions { | ||
file: File; | ||
tonClient: { | ||
client: TonClient | undefined; | ||
}; | ||
sender: Sender; | ||
wallet: string; | ||
} | ||
|
||
export async function uploadFile({ file, tonClient, sender, wallet }: FileUploadOptions) { | ||
const host = 'https://api.bigfiles.cloud' | ||
|
||
const formData = new FormData() | ||
formData.append('file', file) | ||
|
||
if (!tonClient || !sender || !wallet) { | ||
console.log("Wallet not connected") | ||
return; | ||
} | ||
const tonDriveService = tonDrive(tonClient.client!!, sender) | ||
const response = await fetch(`${host}/upload`, { | ||
method: 'POST', | ||
body: formData | ||
}) | ||
|
||
const {bagId} = await response.json() as {bagId: string} | ||
const contractParams = new URLSearchParams() | ||
contractParams.append('bagId', bagId) | ||
contractParams.append('providerAddress', storageProviderAddress.toRawString()) | ||
// TODO: use POST method body instead of query params | ||
const contractResponse = await fetch(new URL('/contracts?' + contractParams.toString(), host).toString(), { | ||
method: 'POST' | ||
}) | ||
const contractFile = await contractResponse.arrayBuffer() | ||
|
||
const base64 = btoa(new Uint8Array(contractFile) | ||
.reduce((data, byte) => data + String.fromCharCode(byte), '')) | ||
|
||
const msgBody = Cell.fromBase64(base64) | ||
const slice = msgBody.beginParse() | ||
const opQueryId = slice.loadUint(32 + 64) | ||
const torrentHash = slice.loadRef().hash().toString('hex') | ||
console.log(`HEX: ${torrentHash}`, BigInt(`0x${torrentHash}`)) | ||
const userCollection = tonDriveService.userCollection(Address.parse(wallet)) | ||
return userCollection.createContract(msgBody, { | ||
name: file.name, | ||
size: file.size | ||
}) | ||
} |
85 changes: 85 additions & 0 deletions
85
ton-drive-frontend/src/features/file/hooks/useUserFiles.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import {useEffect, useState} from "react"; | ||
import type {TonStorageFile} from "../../../entities/file/model/TonStorageFile"; | ||
import {useMyCollection} from "../../drive/hook/useMyCollection"; | ||
import { useRealtimeRemoteState } from "../../../shared/hooks/useRealtimeRemoteState"; | ||
import { FileInfo } from "../../../services/FilesService"; | ||
|
||
export function useUserFiles(): TonStorageFile[] { | ||
const [files, setFiles] = useState<TonStorageFile[]>([]); | ||
const myCollection = useMyCollection() | ||
|
||
useEffect(() => { | ||
if (myCollection == null) { | ||
return | ||
} | ||
myCollection.fileList() | ||
.then(mapFiles) | ||
.then(setFiles) | ||
}, [myCollection]) | ||
|
||
|
||
return files; | ||
} | ||
|
||
export function useRealtimeUserFiles() { | ||
const myCollection = useMyCollection() | ||
|
||
return useRealtimeRemoteState({ | ||
fetchFn: async () => { | ||
if (myCollection == null) { | ||
return []; | ||
} | ||
const files = await myCollection.fileList() | ||
return mapFiles(files) | ||
}, | ||
isEqualFn: (oldFiles, newFiles) => { | ||
if (oldFiles === null) { | ||
return newFiles !== null; | ||
} | ||
if (oldFiles.length !== newFiles.length) { | ||
return false; | ||
} | ||
for (let i = 0; i < oldFiles.length; i++) { | ||
const oldFile = oldFiles[i]; | ||
const newFile = newFiles[i]; | ||
if (oldFile.bagId !== newFile.bagId) { | ||
return false; | ||
} | ||
if (oldFile.storageContractInfo.address?.toRawString() !== newFile.storageContractInfo.address?.toRawString()) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}, | ||
deps: [myCollection] | ||
}) || []; | ||
} | ||
|
||
function mapFiles(files: FileInfo[]): TonStorageFile[] { | ||
return files.map(file => { | ||
const [name, extension] = splitFileName(file.name) | ||
return { | ||
bagId: `${BigInt(file.bagId).toString(16)}`, | ||
name: name, | ||
extension: extension, | ||
//TODO: replace with a proper code | ||
size: parseInt(`${file.fileSize}`), | ||
//TODO: rework once corresponding field is handled by the contract | ||
date: new Date('2021-08-03'), | ||
storageContractInfo: { | ||
address: file.storageContractAddress | ||
} | ||
} | ||
}) | ||
} | ||
|
||
function splitFileName(fileName: string): [string, string] { | ||
const lastDotIndex = fileName.lastIndexOf('.'); | ||
if (lastDotIndex === -1) { | ||
return [fileName, '']; | ||
} | ||
return [ | ||
fileName.substring(0, lastDotIndex), | ||
fileName.substring(lastDotIndex + 1) | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,16 @@ | ||
import FilesNavigation from "../widgets/FilesNavigation" | ||
import FileUpload from "../widgets/FileUpload" | ||
import DriveInfo from "../widgets/DriveInfo"; | ||
import FilesNavigationCard from "../widgets/FilesNavigationCard" | ||
import FileUploadCard from "../widgets/FileUploadCard" | ||
import DriveInfoCard from "../widgets/DriveInfoCard"; | ||
import RequireUserDrive from "../features/drive/ui/RequireUserDrive"; | ||
|
||
export default function FilesListPage() { | ||
return ( | ||
<> | ||
<h1 className="font-bold text-3xl">My Files</h1> | ||
<DriveInfo className="my-2" /> | ||
<FileUpload/> | ||
<FilesNavigation/> | ||
<DriveInfoCard className="my-2" /> | ||
<RequireUserDrive> | ||
<FileUploadCard className="my-2" /> | ||
<FilesNavigationCard className="my-2"/> | ||
</RequireUserDrive> | ||
</> | ||
) | ||
} |
Oops, something went wrong.