Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add list to user collection, add new contracts transfer, burn, add gentk management (cancel, list, burn, transfer) #739

Draft
wants to merge 4 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/Activity/Actions/ActionTransfered.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export const ActionTransfered: TActionComp = ({ action, verbose }) => (
/>
<>
transfered{" "}
<strong>#{verbose ? action.objkt!.name : action.objkt!.iteration}</strong>{" "}
<strong>
{verbose ? action.objkt!.name : `#${action.objkt!.iteration}`}
</strong>{" "}
to
</>
<UserBadge
Expand Down
3 changes: 3 additions & 0 deletions src/components/Input/Checkbox.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
overflow: hidden;
position: relative;
margin-right: 15px;
&.no_children {
margin-right: 0;
}
}

.radio .checkmark {
Expand Down
6 changes: 5 additions & 1 deletion src/components/Input/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ export function Checkbox({
checked={value}
onChange={(event) => onChange(!value, event)}
/>
<span className={cs(style.checkmark, classNameCheckmark)} />
<span
className={cs(style.checkmark, classNameCheckmark, {
[style.no_children]: !children,
})}
/>
{children}
</label>
)
Expand Down
25 changes: 25 additions & 0 deletions src/components/Input/InputMultiIcons.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@import "../../styles/Variables.scss";

.container {
display: flex;
flex-direction: row;
button {
height: 50px;
margin: 0;
padding: 0 4px;
border: none;
background: transparent;
color: var(--color-border-input);
cursor: pointer;

&.active {
pointer-events: none;

color: var(--color-secondary);
}

&:hover {
color: var(--color-secondary);
}
}
}
36 changes: 36 additions & 0 deletions src/components/Input/InputMultiIcons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from "react"
import cs from "classnames"
import style from "./InputMultiIcons.module.scss"

interface Option<T> {
key?: string
label: any
value: T
}
interface Props<T> {
className: string
options: Option<T>[]
value?: T | null
onChange: (opt: Option<T>) => void
}

export function InputMultiIcons<T>({
className,
options,
value = null,
onChange,
}: Props<T>) {
return (
<div className={cs(style.container, className)}>
{options.map((option) => (
<button
key={option.key || (option.value as any)}
className={cs({ [style.active]: option.value === value })}
onClick={() => onChange(option)}
>
{option.label}
</button>
))}
</div>
)
}
3 changes: 2 additions & 1 deletion src/components/Input/InputReactiveSearch.module.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
.root {
display: flex;
flex-direction: column;
width: 400px;
max-width: 400px;
width: 100%;
position: relative;
z-index: 2;
}
Expand Down
32 changes: 32 additions & 0 deletions src/components/TableActions/ModalAddListing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { memo } from "react"
import { Objkt } from "../../types/entities/Objkt"
import { Modal } from "../Utils/Modal"
import style from "./ModalUserCollection.module.scss"

import { ListingCreate } from "../../containers/Objkt/ListingCreate"
import { Spacing } from "../Layout/Spacing"

interface ModalAddListingProps {
objkt: Objkt
onClose: () => void
}

const _ModalAddListing = ({ objkt, onClose }: ModalAddListingProps) => {
return (
<Modal
title={`List for trade "${objkt.name}"`}
onClose={onClose}
width="530px"
>
<div className={style.container}>
<div>Which price would you like to list your gentk for ?</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<div>Which price would you like to list your gentk for ?</div>
<div>What price would you like to set for your listing?</div>

<Spacing size="regular" />
<div className={style.container_create}>
<ListingCreate objkt={objkt} defaultOpen onSuccess={onClose} />
</div>
</div>
</Modal>
)
}

export const ModalAddListing = memo(_ModalAddListing)
81 changes: 81 additions & 0 deletions src/components/TableActions/ModalBurnGentk.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { memo, useCallback, useContext, useState } from "react"
import { Objkt } from "../../types/entities/Objkt"
import { Modal } from "../Utils/Modal"
import style from "./ModalUserCollection.module.scss"
import { Spacing } from "../Layout/Spacing"
import { Button } from "../Button"
import { useContractOperation } from "../../hooks/useContractOperation"
import { ContractFeedback } from "../Feedback/ContractFeedback"
import { UserContext } from "../../containers/UserProvider"
import {
BurnGentkOperation,
TBurnGentkOperationParams,
} from "../../services/contract-operations/BurnGentk"
import { TextWarning } from "../Text/TextWarning"
import { Checkbox } from "../Input/Checkbox"

interface ModalBurnGentkProps {
objkt: Objkt
onClose: () => void
}

const _ModalBurnGentk = ({ objkt, onClose }: ModalBurnGentkProps) => {
const [hasAccept, setHasAccept] = useState(false)
const { user } = useContext(UserContext)
const {
state,
loading: contractLoading,
error: contractError,
success,
call,
} = useContractOperation<TBurnGentkOperationParams>(BurnGentkOperation, {
onSuccess: onClose,
})
const callContract = useCallback(() => {
if (user) {
call({
objkt,
fromTzAddress: user.id,
})
}
}, [call, objkt, user])
return (
<Modal title={`Burn "${objkt.name}"`} onClose={onClose} width="490px">
<div className={style.container}>
<div>Are you sure you want to burn your gentk?</div>
<Spacing size="2x-small" />
<TextWarning>This action is irreversible.</TextWarning>
<Spacing size="regular" />
<Checkbox value={hasAccept} onChange={setHasAccept} paddingLeft={false}>
I understand that my gentk will be permanently deleted.
</Checkbox>
<Button
state={contractLoading ? "loading" : "default"}
color="primary"
onClick={callContract}
size="regular"
className={style.btn_full}
disabled={!hasAccept}
>
<i aria-hidden className="fa-solid fa-fire" />
burn
</Button>
{(contractLoading || success || contractError) && (
<>
<Spacing size="x-small" />
<ContractFeedback
state={state}
loading={contractLoading}
success={success}
error={contractError}
successMessage="Your gentk has been burn"
Copy link
Contributor

@louisholley louisholley May 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
successMessage="Your gentk has been burn"
successMessage="Your gentk has been burned"

noSpacing
/>
</>
)}
</div>
</Modal>
)
}

export const ModalBurnGentk = memo(_ModalBurnGentk)
36 changes: 36 additions & 0 deletions src/components/TableActions/ModalCancelListing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { memo } from "react"
import { Objkt } from "../../types/entities/Objkt"
import { Modal } from "../Utils/Modal"
import style from "./ModalUserCollection.module.scss"

import { Spacing } from "../Layout/Spacing"
import { ListingCancel } from "../../containers/Objkt/ListingCancel"

interface ModalCancelListingProps {
objkt: Objkt
onClose: () => void
}

const _ModalCancelListing = ({ objkt, onClose }: ModalCancelListingProps) => {
return (
<Modal
title={`Cancel listing for "${objkt.name}"`}
onClose={onClose}
width="490px"
>
<div className={style.container}>
<div>Are you sure you want to cancel the listing?</div>
<Spacing size="regular" />
<div className={style.container_create}>
<ListingCancel
listing={objkt.activeListing!}
objkt={objkt}
onSuccess={onClose}
/>
</div>
</div>
</Modal>
)
}

export const ModalCancelListing = memo(_ModalCancelListing)
128 changes: 128 additions & 0 deletions src/components/TableActions/ModalTransferGentk.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { memo, useCallback, useContext, useMemo, useState } from "react"
import { Objkt } from "../../types/entities/Objkt"
import { Modal } from "../Utils/Modal"
import style from "./ModalUserCollection.module.scss"

import { InputSearchUser } from "../Input/InputSearchUser"
import { Spacing } from "../Layout/Spacing"
import { User } from "../../types/entities/User"
import { UserBadge } from "../User/UserBadge"
import { isTezosAddress } from "../../utils/strings"
import { Button } from "../Button"
import { useContractOperation } from "../../hooks/useContractOperation"
import { ContractFeedback } from "../Feedback/ContractFeedback"
import {
TransferGentkOperation,
TTransferGentkOperationParams,
} from "../../services/contract-operations/TransferGentk"
import { UserContext } from "../../containers/UserProvider"

interface ModalTransferGentkProps {
objkt: Objkt
onClose: () => void
}

const _ModalTransferGentk = ({ objkt, onClose }: ModalTransferGentkProps) => {
const { user } = useContext(UserContext)
const {
state,
loading: contractLoading,
error: contractError,
success,
call,
} = useContractOperation<TTransferGentkOperationParams>(
TransferGentkOperation,
{
onSuccess: onClose,
}
)
const [searchValue, setSearchValue] = useState("")
const [fetchedUsers, setFetchedUsers] = useState<User[]>([])
const handleSelectUser = useCallback((tzAddress) => {
setSearchValue(tzAddress)
}, [])

const userSelected = useMemo(() => {
return fetchedUsers.find((user) => user.id === searchValue)
}, [fetchedUsers, searchValue])
const callContract = useCallback(() => {
if (user) {
call({
objkt,
fromTzAddress: user.id,
toTzAddress: searchValue,
toUsername: userSelected ? userSelected.name : undefined,
})
}
}, [call, objkt, searchValue, user, userSelected])
const hasValidAddress = isTezosAddress(searchValue)
return (
<Modal
title={`Transfer "${objkt.name}" to a tezos address`}
onClose={onClose}
width="600px"
>
<div className={style.container}>
<div>
Please enter a valid tezos address or search by username to transfer
your gentk.
</div>
<Spacing size="regular" />
<div className={style.container_search}>
<div className={style.container_search_row}>
<InputSearchUser
value={searchValue}
onChange={handleSelectUser}
displayAddress
onFetchUsers={setFetchedUsers}
/>
<Button
state={contractLoading ? "loading" : "default"}
color="secondary"
onClick={callContract}
size="regular"
disabled={!hasValidAddress}
className={style.btn_transfer}
>
<i aria-hidden className="fa-solid fa-arrow-right-arrow-left" />
transfer
</Button>
</div>
{hasValidAddress && (
<>
<Spacing size="regular" />
<div>
You will transfer your gentk to{" "}
{userSelected ? (
<UserBadge
user={userSelected}
hasLink
displayAvatar={false}
/>
) : (
<span className={style.tz_address}>{searchValue}</span>
)}
{"."}
</div>
</>
)}
{(contractLoading || success || contractError) && (
<>
<Spacing size="x-small" />
<ContractFeedback
state={state}
loading={contractLoading}
success={success}
error={contractError}
successMessage="Your Gentk has been transfered"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
successMessage="Your Gentk has been transfered"
successMessage="Your Gentk has been transferred"

noSpacing
/>
</>
)}
</div>
</div>
</Modal>
)
}

export const ModalTransferGentk = memo(_ModalTransferGentk)
Loading