fix freebie dialog (#460)
This commit is contained in:
parent
589b15b597
commit
a318727f9c
@ -643,6 +643,9 @@ export default {
|
||||
if (Number(old.userId) !== Number(me?.id)) {
|
||||
throw new GraphQLError('item does not belong to you', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
if (old.bio) {
|
||||
throw new GraphQLError('cannot delete bio', { extensions: { code: 'BAD_INPUT' } })
|
||||
}
|
||||
|
||||
return await deleteItemByAuthor({ models, id, item: old })
|
||||
},
|
||||
@ -1171,7 +1174,7 @@ export const SELECT =
|
||||
"Item"."rootId", "Item".upvotes, "Item".company, "Item".location, "Item".remote, "Item"."deletedAt",
|
||||
"Item"."subName", "Item".status, "Item"."uploadId", "Item"."pollCost", "Item".boost, "Item".msats,
|
||||
"Item".ncomments, "Item"."commentMsats", "Item"."lastCommentAt", "Item"."weightedVotes",
|
||||
"Item"."weightedDownVotes", "Item".freebie, "Item"."otsHash", "Item"."bountyPaidTo",
|
||||
"Item"."weightedDownVotes", "Item".freebie, "Item".bio, "Item"."otsHash", "Item"."bountyPaidTo",
|
||||
ltree2text("Item"."path") AS "path", "Item"."weightedComments", "Item"."imgproxyUrls"`
|
||||
|
||||
function topOrderByWeightedSats (me, models) {
|
||||
|
@ -94,6 +94,7 @@ export default gql`
|
||||
meForward: Boolean
|
||||
outlawed: Boolean!
|
||||
freebie: Boolean!
|
||||
bio: Boolean!
|
||||
paidImgLink: Boolean
|
||||
ncomments: Int!
|
||||
comments(sort: String): [Item!]!
|
||||
|
@ -3,15 +3,14 @@ import { useRouter } from 'next/router'
|
||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import FeeButton from './fee-button'
|
||||
import InputGroup from 'react-bootstrap/InputGroup'
|
||||
import { bountySchema } from '../lib/validate'
|
||||
import { SubSelectInitial } from './sub-select-form'
|
||||
import CancelButton from './cancel-button'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { useMe } from './me'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
export function BountyForm ({
|
||||
item,
|
||||
@ -20,7 +19,6 @@ export function BountyForm ({
|
||||
titleLabel = 'title',
|
||||
bountyLabel = 'bounty',
|
||||
textLabel = 'text',
|
||||
buttonText = 'post',
|
||||
handleSubmit,
|
||||
children
|
||||
}) {
|
||||
@ -133,13 +131,7 @@ export function BountyForm ({
|
||||
}
|
||||
/>
|
||||
<AdvPostForm edit={!!item} />
|
||||
<div className='d-flex mt-3'>
|
||||
<CancelButton />
|
||||
<FeeButton
|
||||
text={buttonText}
|
||||
variant='secondary'
|
||||
/>
|
||||
</div>
|
||||
<ItemButtonBar itemId={item?.id} canDelete={false} />
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { Form, MarkdownInput } from '../components/form'
|
||||
import { gql, useMutation } from '@apollo/client'
|
||||
import styles from './reply.module.css'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
import Delete from './delete'
|
||||
import { commentSchema } from '../lib/validate'
|
||||
import FeeButton, { FeeButtonProvider } from './fee-button'
|
||||
import { FeeButtonProvider } from './fee-button'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
export default function CommentEdit ({ comment, editThreshold, onSuccess, onCancel }) {
|
||||
const [upsertComment] = useMutation(
|
||||
@ -51,17 +50,7 @@ export default function CommentEdit ({ comment, editThreshold, onSuccess, onCanc
|
||||
autoFocus
|
||||
required
|
||||
/>
|
||||
<div className='d-flex justify-content-between'>
|
||||
<Delete itemId={comment.id} onDelete={onSuccess} type='comment'>
|
||||
<Button variant='grey-medium'>delete</Button>
|
||||
</Delete>
|
||||
<div className='d-flex mt-3'>
|
||||
<FeeButton
|
||||
text='save'
|
||||
variant='secondary'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ItemButtonBar itemId={comment.id} onDelete={onSuccess} hasCancel={false} />
|
||||
</Form>
|
||||
</FeeButtonProvider>
|
||||
</div>
|
||||
|
@ -3,24 +3,21 @@ import { useRouter } from 'next/router'
|
||||
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import FeeButton from './fee-button'
|
||||
import { ITEM_FIELDS } from '../fragments/items'
|
||||
import AccordianItem from './accordian-item'
|
||||
import Item from './item'
|
||||
import Delete from './delete'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
import { discussionSchema } from '../lib/validate'
|
||||
import { SubSelectInitial } from './sub-select-form'
|
||||
import CancelButton from './cancel-button'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { useMe } from './me'
|
||||
import useCrossposter from './use-crossposter'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
export function DiscussionForm ({
|
||||
item, sub, editThreshold, titleLabel = 'title',
|
||||
textLabel = 'text', buttonText = 'post',
|
||||
textLabel = 'text',
|
||||
handleSubmit, children
|
||||
}) {
|
||||
const router = useRouter()
|
||||
@ -133,21 +130,7 @@ export function DiscussionForm ({
|
||||
: null}
|
||||
/>
|
||||
<AdvPostForm edit={!!item} />
|
||||
<div className='mt-3'>
|
||||
<div className='d-flex justify-content-between'>
|
||||
{item &&
|
||||
<Delete itemId={item.id} onDelete={() => router.push(`/items/${item.id}`)}>
|
||||
<Button variant='grey-medium'>delete</Button>
|
||||
</Delete>}
|
||||
<div className='d-flex align-items-center ms-auto'>
|
||||
<CancelButton />
|
||||
<FeeButton
|
||||
text={buttonText}
|
||||
variant='secondary'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ItemButtonBar itemId={item?.id} />
|
||||
{!item &&
|
||||
<div className={`mt-3 ${related.length > 0 ? '' : 'invisible'}`}>
|
||||
<AccordianItem
|
||||
|
@ -4,7 +4,7 @@ import ActionTooltip from './action-tooltip'
|
||||
import Info from './info'
|
||||
import styles from './fee-button.module.css'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { SSR } from '../lib/constants'
|
||||
import { FREEBIE_BASE_COST_THRESHOLD, SSR } from '../lib/constants'
|
||||
import { numWithUnits } from '../lib/format'
|
||||
import { useMe } from './me'
|
||||
import AnonIcon from '../svgs/spy-fill.svg'
|
||||
@ -97,20 +97,39 @@ export function useFeeButton () {
|
||||
return useContext(FeeButtonContext)
|
||||
}
|
||||
|
||||
function FreebieDialog () {
|
||||
return (
|
||||
<>
|
||||
<div className='fw-bold'>you don't have enough sats, so this one is on us</div>
|
||||
<ul className='mt-2'>
|
||||
<li>Free items have limited visibility until other stackers zap them.</li>
|
||||
<li>To get fully visibile right away, fund your account with a few sats or earn some on Stacker News.</li>
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default function FeeButton ({ ChildButton = SubmitButton, variant, text, disabled }) {
|
||||
const me = useMe()
|
||||
const { lines, total, disabled: ctxDisabled } = useFeeButton()
|
||||
// freebies: there's only a base cost, it's less than 10, and we have less than 10 sats
|
||||
const free = total === lines.baseCost?.modifier(0) &&
|
||||
total <= FREEBIE_BASE_COST_THRESHOLD &&
|
||||
me?.sats < FREEBIE_BASE_COST_THRESHOLD
|
||||
const feeText = free
|
||||
? 'free'
|
||||
: total > 1
|
||||
? numWithUnits(total, { abbreviate: false, format: true })
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<div className={styles.feeButton}>
|
||||
<ActionTooltip overlayText={numWithUnits(total, { abbreviate: false })}>
|
||||
<ChildButton variant={variant} disabled={disabled || ctxDisabled}>{text}{total > 1 && <small> {numWithUnits(total, { abbreviate: false, format: true })}</small>}</ChildButton>
|
||||
<ChildButton variant={variant} disabled={disabled || ctxDisabled}>{text}{feeText && <small> {feeText}</small>}</ChildButton>
|
||||
</ActionTooltip>
|
||||
{!me && <AnonInfo />}
|
||||
{total > 1 &&
|
||||
<Info>
|
||||
<Receipt lines={lines} total={total} />
|
||||
</Info>}
|
||||
{(free && <Info><FreebieDialog /></Info>) ||
|
||||
(total > 1 && <Info><Receipt lines={lines} total={total} /></Info>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ export default function ItemInfo ({
|
||||
</Link>}
|
||||
{me && !item.meSats && !item.position &&
|
||||
!item.mine && !item.deletedAt && <DontLikeThisDropdownItem id={item.id} />}
|
||||
{item.mine && !item.position && !item.deletedAt &&
|
||||
{item.mine && !item.position && !item.deletedAt && !item.bio &&
|
||||
<DeleteDropdownItem itemId={item.id} type={item.title ? 'post' : 'comment'} />}
|
||||
{me && !item.mine &&
|
||||
<>
|
||||
|
@ -15,9 +15,8 @@ import Link from 'next/link'
|
||||
import { usePrice } from './price'
|
||||
import Avatar from './avatar'
|
||||
import { jobSchema } from '../lib/validate'
|
||||
import CancelButton from './cancel-button'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import FeeButton from './fee-button'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
function satsMin2Mo (minute) {
|
||||
return minute * 30 * 24 * 60
|
||||
@ -155,13 +154,7 @@ export default function JobForm ({ item, sub }) {
|
||||
/>
|
||||
<PromoteJob item={item} sub={sub} />
|
||||
{item && <StatusControl item={item} />}
|
||||
<div className='d-flex align-items-center justify-content-end mt-3'>
|
||||
<CancelButton />
|
||||
<FeeButton
|
||||
text={item ? 'save' : 'post'}
|
||||
variant='secondary'
|
||||
/>
|
||||
</div>
|
||||
<ItemButtonBar itemId={item?.id} canDelete={false} />
|
||||
</Form>
|
||||
</>
|
||||
)
|
||||
|
@ -7,16 +7,13 @@ import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import { ITEM_FIELDS } from '../fragments/items'
|
||||
import Item from './item'
|
||||
import AccordianItem from './accordian-item'
|
||||
import FeeButton from './fee-button'
|
||||
import Delete from './delete'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
import { linkSchema } from '../lib/validate'
|
||||
import Moon from '../svgs/moon-fill.svg'
|
||||
import { SubSelectInitial } from './sub-select-form'
|
||||
import CancelButton from './cancel-button'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { useMe } from './me'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
export function LinkForm ({ item, sub, editThreshold, children }) {
|
||||
const router = useRouter()
|
||||
@ -193,26 +190,13 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
|
||||
minRows={2}
|
||||
/>
|
||||
</AdvPostForm>
|
||||
<div className='mt-3'>
|
||||
<div className='d-flex justify-content-between'>
|
||||
{item
|
||||
? (
|
||||
<Delete itemId={item.id} onDelete={() => router.push(`/items/${item.id}`)}>
|
||||
<Button variant='grey-medium'>delete</Button>
|
||||
</Delete>)
|
||||
: dupesLoading &&
|
||||
<div className='d-flex justify-content-center'>
|
||||
<Moon className='spin fill-grey' />
|
||||
<div className='ms-2 text-muted' style={{ fontWeight: '600' }}>searching for dupes</div>
|
||||
</div>}
|
||||
<div className='d-flex align-items-center ms-auto'>
|
||||
<CancelButton />
|
||||
<FeeButton
|
||||
text={item ? 'save' : 'post'} disabled={postDisabled} variant='secondary'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ItemButtonBar itemId={item?.id} disable={postDisabled}>
|
||||
{!item && dupesLoading &&
|
||||
<div className='d-flex justify-content-center'>
|
||||
<Moon className='spin fill-grey' />
|
||||
<div className='ms-2 text-muted' style={{ fontWeight: '600' }}>searching for dupes</div>
|
||||
</div>}
|
||||
</ItemButtonBar>
|
||||
{!item &&
|
||||
<>
|
||||
{dupesData?.dupes?.length > 0 &&
|
||||
|
@ -4,15 +4,12 @@ import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||
import Countdown from './countdown'
|
||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import FeeButton from './fee-button'
|
||||
import Delete from './delete'
|
||||
import Button from 'react-bootstrap/Button'
|
||||
import { pollSchema } from '../lib/validate'
|
||||
import { SubSelectInitial } from './sub-select-form'
|
||||
import CancelButton from './cancel-button'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { useMe } from './me'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
export function PollForm ({ item, sub, editThreshold, children }) {
|
||||
const router = useRouter()
|
||||
@ -98,22 +95,7 @@ export function PollForm ({ item, sub, editThreshold, children }) {
|
||||
maxLength={MAX_POLL_CHOICE_LENGTH}
|
||||
/>
|
||||
<AdvPostForm edit={!!item} />
|
||||
<div className='mt-3'>
|
||||
<div className='mt-3'>
|
||||
<div className='d-flex justify-content-between'>
|
||||
{item &&
|
||||
<Delete itemId={item.id} onDelete={() => router.push(`/items/${item.id}`)}>
|
||||
<Button variant='grey-medium'>delete</Button>
|
||||
</Delete>}
|
||||
<div className='d-flex align-items-center ms-auto'>
|
||||
<CancelButton />
|
||||
<FeeButton
|
||||
text={item ? 'save' : 'post'} variant='secondary'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ItemButtonBar itemId={item?.id} />
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
@ -10,24 +10,10 @@ import { LinkForm } from './link-form'
|
||||
import { PollForm } from './poll-form'
|
||||
import { BountyForm } from './bounty-form'
|
||||
import SubSelect from './sub-select-form'
|
||||
import Info from './info'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
||||
|
||||
function FreebieDialog () {
|
||||
return (
|
||||
<div className='text-center mb-4 text-muted'>
|
||||
you have no sats, so this one is on us
|
||||
<Info>
|
||||
<ul className='fw-bold'>
|
||||
<li>Free posts have limited visibility and are hidden on the recent tab until other stackers zap them.</li>
|
||||
<li>Free posts will not cover posts that cost more than 1 sat.</li>
|
||||
<li>To get fully visibile and unrestricted posts right away, fund your account with a few sats or earn some on Stacker News.</li>
|
||||
</ul>
|
||||
</Info>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import FeeButton, { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
||||
import Delete from './delete'
|
||||
import CancelButton from './cancel-button'
|
||||
|
||||
export function PostForm ({ type, sub, children }) {
|
||||
const me = useMe()
|
||||
@ -49,7 +35,6 @@ export function PostForm ({ type, sub, children }) {
|
||||
<Alert className='position-absolute' style={{ top: '-6rem' }} variant='danger' onClose={() => setErrorMessage(undefined)} dismissible>
|
||||
{errorMessage}
|
||||
</Alert>}
|
||||
{me?.sats < 1 && <FreebieDialog />}
|
||||
<SubSelect noForm sub={sub?.name} />
|
||||
<Link href={prefix + '/post?type=link'}>
|
||||
<Button variant='secondary'>link</Button>
|
||||
@ -121,3 +106,34 @@ export default function Post ({ sub }) {
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function ItemButtonBar ({
|
||||
itemId, canDelete = true, disable,
|
||||
className, children, onDelete, onCancel, hasCancel = true,
|
||||
createText = 'post', editText = 'save'
|
||||
}) {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<div className={`mt-3 ${className}`}>
|
||||
<div className='d-flex justify-content-between'>
|
||||
{itemId && canDelete &&
|
||||
<Delete
|
||||
itemId={itemId}
|
||||
onDelete={onDelete || (() => router.push(`/items/${itemId}`))}
|
||||
>
|
||||
<Button variant='grey-medium'>delete</Button>
|
||||
</Delete>}
|
||||
{children}
|
||||
<div className='d-flex align-items-center ms-auto'>
|
||||
{hasCancel && <CancelButton onClick={onCancel} />}
|
||||
<FeeButton
|
||||
text={itemId ? editText : createText}
|
||||
variant='secondary'
|
||||
disabled={disable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import { COMMENTS } from '../fragments/comments'
|
||||
import { useMe } from './me'
|
||||
import { forwardRef, useCallback, useEffect, useState, useRef, useImperativeHandle } from 'react'
|
||||
import Link from 'next/link'
|
||||
import FeeButton, { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
||||
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
|
||||
import { commentsViewedAfterComment } from '../lib/new-comments'
|
||||
import { commentSchema } from '../lib/validate'
|
||||
import Info from './info'
|
||||
import { quote } from '../lib/md'
|
||||
import { COMMENT_DEPTH_LIMIT } from '../lib/constants'
|
||||
import { ItemButtonBar } from './post'
|
||||
|
||||
export function ReplyOnAnotherPage ({ item }) {
|
||||
const path = item.path.split('.')
|
||||
@ -28,21 +28,6 @@ export function ReplyOnAnotherPage ({ item }) {
|
||||
)
|
||||
}
|
||||
|
||||
function FreebieDialog () {
|
||||
return (
|
||||
<div className='text-muted'>
|
||||
you have no sats, so this one is on us
|
||||
<Info>
|
||||
<ul className='fw-bold'>
|
||||
<li>Free comments have limited visibility and are listed at the bottom of the comment section until other stackers zap them.</li>
|
||||
<li>Free comments will not cover comments that cost more than 1 sat.</li>
|
||||
<li>To get fully visibile and unrestricted comments right away, fund your account with a few sats or earn some on Stacker News.</li>
|
||||
</ul>
|
||||
</Info>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children, placeholder, contentContainerRef }, ref) {
|
||||
const [reply, setReply] = useState(replyOpen)
|
||||
const me = useMe()
|
||||
@ -205,18 +190,9 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
|
||||
autoFocus={!replyOpen}
|
||||
required
|
||||
placeholder={placeholder}
|
||||
hint={me?.sats < 1 && <FreebieDialog />}
|
||||
innerRef={replyInput}
|
||||
/>
|
||||
<div className='d-flex mt-1'>
|
||||
<div className='ms-auto'>
|
||||
<FeeButton
|
||||
text='reply'
|
||||
variant='secondary'
|
||||
alwaysShow
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ItemButtonBar createText='reply' hasCancel={false} />
|
||||
</Form>
|
||||
</FeeButtonProvider>
|
||||
</div>}
|
||||
|
@ -33,6 +33,7 @@ export const ITEM_FIELDS = gql`
|
||||
meForward
|
||||
outlawed
|
||||
freebie
|
||||
bio
|
||||
ncomments
|
||||
commentSats
|
||||
lastCommentAt
|
||||
|
@ -57,6 +57,7 @@ export const MAX_FORWARDS = 5
|
||||
export const LNURLP_COMMENT_MAX_LENGTH = 1000
|
||||
export const RESERVED_MAX_USER_ID = 615
|
||||
export const GLOBAL_SEED = 616
|
||||
export const FREEBIE_BASE_COST_THRESHOLD = 10
|
||||
|
||||
export const FOUND_BLURBS = [
|
||||
'The harsh frontier is no place for the unprepared. This hat will protect you from the sun, dust, and other elements Mother Nature throws your way.',
|
||||
|
@ -10,11 +10,11 @@ import { useMe } from '../../components/me'
|
||||
import { USER_FULL } from '../../fragments/users'
|
||||
import { ITEM_FIELDS } from '../../fragments/items'
|
||||
import { getGetServerSideProps } from '../../api/ssrApollo'
|
||||
import FeeButton, { FeeButtonProvider } from '../../components/fee-button'
|
||||
import { FeeButtonProvider } from '../../components/fee-button'
|
||||
import { bioSchema } from '../../lib/validate'
|
||||
import CancelButton from '../../components/cancel-button'
|
||||
import { useRouter } from 'next/router'
|
||||
import PageLoading from '../../components/page-loading'
|
||||
import { ItemButtonBar } from '../../components/post'
|
||||
|
||||
export const getServerSideProps = getGetServerSideProps({
|
||||
query: USER_FULL,
|
||||
@ -68,12 +68,7 @@ export function BioForm ({ handleDone, bio }) {
|
||||
name='bio'
|
||||
minRows={6}
|
||||
/>
|
||||
<div className='d-flex mt-3 justify-content-end'>
|
||||
<CancelButton onClick={handleDone} />
|
||||
<FeeButtonProvider>
|
||||
<FeeButton text='save' variant='secondary' />
|
||||
</FeeButtonProvider>
|
||||
</div>
|
||||
<ItemButtonBar createText='save' onCancel={handleDone} />
|
||||
</Form>
|
||||
</FeeButtonProvider>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user