fix freebie dialog (#460)

This commit is contained in:
keyan 2023-11-19 14:16:35 -06:00
parent 589b15b597
commit a318727f9c
15 changed files with 93 additions and 158 deletions

View File

@ -643,6 +643,9 @@ export default {
if (Number(old.userId) !== Number(me?.id)) { if (Number(old.userId) !== Number(me?.id)) {
throw new GraphQLError('item does not belong to you', { extensions: { code: 'FORBIDDEN' } }) 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 }) 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"."rootId", "Item".upvotes, "Item".company, "Item".location, "Item".remote, "Item"."deletedAt",
"Item"."subName", "Item".status, "Item"."uploadId", "Item"."pollCost", "Item".boost, "Item".msats, "Item"."subName", "Item".status, "Item"."uploadId", "Item"."pollCost", "Item".boost, "Item".msats,
"Item".ncomments, "Item"."commentMsats", "Item"."lastCommentAt", "Item"."weightedVotes", "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"` ltree2text("Item"."path") AS "path", "Item"."weightedComments", "Item"."imgproxyUrls"`
function topOrderByWeightedSats (me, models) { function topOrderByWeightedSats (me, models) {

View File

@ -94,6 +94,7 @@ export default gql`
meForward: Boolean meForward: Boolean
outlawed: Boolean! outlawed: Boolean!
freebie: Boolean! freebie: Boolean!
bio: Boolean!
paidImgLink: Boolean paidImgLink: Boolean
ncomments: Int! ncomments: Int!
comments(sort: String): [Item!]! comments(sort: String): [Item!]!

View File

@ -3,15 +3,14 @@ import { useRouter } from 'next/router'
import { gql, useApolloClient, useMutation } from '@apollo/client' import { gql, useApolloClient, useMutation } from '@apollo/client'
import Countdown from './countdown' import Countdown from './countdown'
import AdvPostForm, { AdvPostInitial } from './adv-post-form' import AdvPostForm, { AdvPostInitial } from './adv-post-form'
import FeeButton from './fee-button'
import InputGroup from 'react-bootstrap/InputGroup' import InputGroup from 'react-bootstrap/InputGroup'
import { bountySchema } from '../lib/validate' import { bountySchema } from '../lib/validate'
import { SubSelectInitial } from './sub-select-form' import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
import { useCallback } from 'react' import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form' import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants' import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me' import { useMe } from './me'
import { ItemButtonBar } from './post'
export function BountyForm ({ export function BountyForm ({
item, item,
@ -20,7 +19,6 @@ export function BountyForm ({
titleLabel = 'title', titleLabel = 'title',
bountyLabel = 'bounty', bountyLabel = 'bounty',
textLabel = 'text', textLabel = 'text',
buttonText = 'post',
handleSubmit, handleSubmit,
children children
}) { }) {
@ -133,13 +131,7 @@ export function BountyForm ({
} }
/> />
<AdvPostForm edit={!!item} /> <AdvPostForm edit={!!item} />
<div className='d-flex mt-3'> <ItemButtonBar itemId={item?.id} canDelete={false} />
<CancelButton />
<FeeButton
text={buttonText}
variant='secondary'
/>
</div>
</Form> </Form>
) )
} }

View File

@ -1,10 +1,9 @@
import { Form, MarkdownInput } from '../components/form' import { Form, MarkdownInput } from '../components/form'
import { gql, useMutation } from '@apollo/client' import { gql, useMutation } from '@apollo/client'
import styles from './reply.module.css' import styles from './reply.module.css'
import Button from 'react-bootstrap/Button'
import Delete from './delete'
import { commentSchema } from '../lib/validate' 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 }) { export default function CommentEdit ({ comment, editThreshold, onSuccess, onCancel }) {
const [upsertComment] = useMutation( const [upsertComment] = useMutation(
@ -51,17 +50,7 @@ export default function CommentEdit ({ comment, editThreshold, onSuccess, onCanc
autoFocus autoFocus
required required
/> />
<div className='d-flex justify-content-between'> <ItemButtonBar itemId={comment.id} onDelete={onSuccess} hasCancel={false} />
<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>
</Form> </Form>
</FeeButtonProvider> </FeeButtonProvider>
</div> </div>

View File

@ -3,24 +3,21 @@ import { useRouter } from 'next/router'
import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client' import { gql, useApolloClient, useLazyQuery, useMutation } from '@apollo/client'
import Countdown from './countdown' import Countdown from './countdown'
import AdvPostForm, { AdvPostInitial } from './adv-post-form' import AdvPostForm, { AdvPostInitial } from './adv-post-form'
import FeeButton from './fee-button'
import { ITEM_FIELDS } from '../fragments/items' import { ITEM_FIELDS } from '../fragments/items'
import AccordianItem from './accordian-item' import AccordianItem from './accordian-item'
import Item from './item' import Item from './item'
import Delete from './delete'
import Button from 'react-bootstrap/Button'
import { discussionSchema } from '../lib/validate' import { discussionSchema } from '../lib/validate'
import { SubSelectInitial } from './sub-select-form' import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
import { useCallback } from 'react' import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form' import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants' import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me' import { useMe } from './me'
import useCrossposter from './use-crossposter' import useCrossposter from './use-crossposter'
import { ItemButtonBar } from './post'
export function DiscussionForm ({ export function DiscussionForm ({
item, sub, editThreshold, titleLabel = 'title', item, sub, editThreshold, titleLabel = 'title',
textLabel = 'text', buttonText = 'post', textLabel = 'text',
handleSubmit, children handleSubmit, children
}) { }) {
const router = useRouter() const router = useRouter()
@ -133,21 +130,7 @@ export function DiscussionForm ({
: null} : null}
/> />
<AdvPostForm edit={!!item} /> <AdvPostForm edit={!!item} />
<div className='mt-3'> <ItemButtonBar itemId={item?.id} />
<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>
{!item && {!item &&
<div className={`mt-3 ${related.length > 0 ? '' : 'invisible'}`}> <div className={`mt-3 ${related.length > 0 ? '' : 'invisible'}`}>
<AccordianItem <AccordianItem

View File

@ -4,7 +4,7 @@ import ActionTooltip from './action-tooltip'
import Info from './info' import Info from './info'
import styles from './fee-button.module.css' import styles from './fee-button.module.css'
import { gql, useQuery } from '@apollo/client' 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 { numWithUnits } from '../lib/format'
import { useMe } from './me' import { useMe } from './me'
import AnonIcon from '../svgs/spy-fill.svg' import AnonIcon from '../svgs/spy-fill.svg'
@ -97,20 +97,39 @@ export function useFeeButton () {
return useContext(FeeButtonContext) 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 }) { export default function FeeButton ({ ChildButton = SubmitButton, variant, text, disabled }) {
const me = useMe() const me = useMe()
const { lines, total, disabled: ctxDisabled } = useFeeButton() 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 ( return (
<div className={styles.feeButton}> <div className={styles.feeButton}>
<ActionTooltip overlayText={numWithUnits(total, { abbreviate: false })}> <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> </ActionTooltip>
{!me && <AnonInfo />} {!me && <AnonInfo />}
{total > 1 && {(free && <Info><FreebieDialog /></Info>) ||
<Info> (total > 1 && <Info><Receipt lines={lines} total={total} /></Info>)}
<Receipt lines={lines} total={total} />
</Info>}
</div> </div>
) )
} }

View File

@ -144,7 +144,7 @@ export default function ItemInfo ({
</Link>} </Link>}
{me && !item.meSats && !item.position && {me && !item.meSats && !item.position &&
!item.mine && !item.deletedAt && <DontLikeThisDropdownItem id={item.id} />} !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'} />} <DeleteDropdownItem itemId={item.id} type={item.title ? 'post' : 'comment'} />}
{me && !item.mine && {me && !item.mine &&
<> <>

View File

@ -15,9 +15,8 @@ import Link from 'next/link'
import { usePrice } from './price' import { usePrice } from './price'
import Avatar from './avatar' import Avatar from './avatar'
import { jobSchema } from '../lib/validate' import { jobSchema } from '../lib/validate'
import CancelButton from './cancel-button'
import { MAX_TITLE_LENGTH } from '../lib/constants' import { MAX_TITLE_LENGTH } from '../lib/constants'
import FeeButton from './fee-button' import { ItemButtonBar } from './post'
function satsMin2Mo (minute) { function satsMin2Mo (minute) {
return minute * 30 * 24 * 60 return minute * 30 * 24 * 60
@ -155,13 +154,7 @@ export default function JobForm ({ item, sub }) {
/> />
<PromoteJob item={item} sub={sub} /> <PromoteJob item={item} sub={sub} />
{item && <StatusControl item={item} />} {item && <StatusControl item={item} />}
<div className='d-flex align-items-center justify-content-end mt-3'> <ItemButtonBar itemId={item?.id} canDelete={false} />
<CancelButton />
<FeeButton
text={item ? 'save' : 'post'}
variant='secondary'
/>
</div>
</Form> </Form>
</> </>
) )

View File

@ -7,16 +7,13 @@ import AdvPostForm, { AdvPostInitial } from './adv-post-form'
import { ITEM_FIELDS } from '../fragments/items' import { ITEM_FIELDS } from '../fragments/items'
import Item from './item' import Item from './item'
import AccordianItem from './accordian-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 { linkSchema } from '../lib/validate'
import Moon from '../svgs/moon-fill.svg' import Moon from '../svgs/moon-fill.svg'
import { SubSelectInitial } from './sub-select-form' import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
import { normalizeForwards } from '../lib/form' import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants' import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me' import { useMe } from './me'
import { ItemButtonBar } from './post'
export function LinkForm ({ item, sub, editThreshold, children }) { export function LinkForm ({ item, sub, editThreshold, children }) {
const router = useRouter() const router = useRouter()
@ -193,26 +190,13 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
minRows={2} minRows={2}
/> />
</AdvPostForm> </AdvPostForm>
<div className='mt-3'> <ItemButtonBar itemId={item?.id} disable={postDisabled}>
<div className='d-flex justify-content-between'> {!item && dupesLoading &&
{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'> <div className='d-flex justify-content-center'>
<Moon className='spin fill-grey' /> <Moon className='spin fill-grey' />
<div className='ms-2 text-muted' style={{ fontWeight: '600' }}>searching for dupes</div> <div className='ms-2 text-muted' style={{ fontWeight: '600' }}>searching for dupes</div>
</div>} </div>}
<div className='d-flex align-items-center ms-auto'> </ItemButtonBar>
<CancelButton />
<FeeButton
text={item ? 'save' : 'post'} disabled={postDisabled} variant='secondary'
/>
</div>
</div>
</div>
{!item && {!item &&
<> <>
{dupesData?.dupes?.length > 0 && {dupesData?.dupes?.length > 0 &&

View File

@ -4,15 +4,12 @@ import { gql, useApolloClient, useMutation } from '@apollo/client'
import Countdown from './countdown' import Countdown from './countdown'
import AdvPostForm, { AdvPostInitial } from './adv-post-form' import AdvPostForm, { AdvPostInitial } from './adv-post-form'
import { MAX_POLL_CHOICE_LENGTH, MAX_POLL_NUM_CHOICES, MAX_TITLE_LENGTH } from '../lib/constants' 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 { pollSchema } from '../lib/validate'
import { SubSelectInitial } from './sub-select-form' import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
import { useCallback } from 'react' import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form' import { normalizeForwards } from '../lib/form'
import { useMe } from './me' import { useMe } from './me'
import { ItemButtonBar } from './post'
export function PollForm ({ item, sub, editThreshold, children }) { export function PollForm ({ item, sub, editThreshold, children }) {
const router = useRouter() const router = useRouter()
@ -98,22 +95,7 @@ export function PollForm ({ item, sub, editThreshold, children }) {
maxLength={MAX_POLL_CHOICE_LENGTH} maxLength={MAX_POLL_CHOICE_LENGTH}
/> />
<AdvPostForm edit={!!item} /> <AdvPostForm edit={!!item} />
<div className='mt-3'> <ItemButtonBar itemId={item?.id} />
<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>
</Form> </Form>
) )
} }

View File

@ -10,24 +10,10 @@ import { LinkForm } from './link-form'
import { PollForm } from './poll-form' import { PollForm } from './poll-form'
import { BountyForm } from './bounty-form' import { BountyForm } from './bounty-form'
import SubSelect from './sub-select-form' import SubSelect from './sub-select-form'
import Info from './info'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button' import FeeButton, { FeeButtonProvider, postCommentBaseLineItems, postCommentUseRemoteLineItems } from './fee-button'
import Delete from './delete'
function FreebieDialog () { import CancelButton from './cancel-button'
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>
)
}
export function PostForm ({ type, sub, children }) { export function PostForm ({ type, sub, children }) {
const me = useMe() 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> <Alert className='position-absolute' style={{ top: '-6rem' }} variant='danger' onClose={() => setErrorMessage(undefined)} dismissible>
{errorMessage} {errorMessage}
</Alert>} </Alert>}
{me?.sats < 1 && <FreebieDialog />}
<SubSelect noForm sub={sub?.name} /> <SubSelect noForm sub={sub?.name} />
<Link href={prefix + '/post?type=link'}> <Link href={prefix + '/post?type=link'}>
<Button variant='secondary'>link</Button> <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>
)
}

View File

@ -5,12 +5,12 @@ import { COMMENTS } from '../fragments/comments'
import { useMe } from './me' import { useMe } from './me'
import { forwardRef, useCallback, useEffect, useState, useRef, useImperativeHandle } from 'react' import { forwardRef, useCallback, useEffect, useState, useRef, useImperativeHandle } from 'react'
import Link from 'next/link' 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 { commentsViewedAfterComment } from '../lib/new-comments'
import { commentSchema } from '../lib/validate' import { commentSchema } from '../lib/validate'
import Info from './info'
import { quote } from '../lib/md' import { quote } from '../lib/md'
import { COMMENT_DEPTH_LIMIT } from '../lib/constants' import { COMMENT_DEPTH_LIMIT } from '../lib/constants'
import { ItemButtonBar } from './post'
export function ReplyOnAnotherPage ({ item }) { export function ReplyOnAnotherPage ({ item }) {
const path = item.path.split('.') 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) { export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children, placeholder, contentContainerRef }, ref) {
const [reply, setReply] = useState(replyOpen) const [reply, setReply] = useState(replyOpen)
const me = useMe() const me = useMe()
@ -205,18 +190,9 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
autoFocus={!replyOpen} autoFocus={!replyOpen}
required required
placeholder={placeholder} placeholder={placeholder}
hint={me?.sats < 1 && <FreebieDialog />}
innerRef={replyInput} innerRef={replyInput}
/> />
<div className='d-flex mt-1'> <ItemButtonBar createText='reply' hasCancel={false} />
<div className='ms-auto'>
<FeeButton
text='reply'
variant='secondary'
alwaysShow
/>
</div>
</div>
</Form> </Form>
</FeeButtonProvider> </FeeButtonProvider>
</div>} </div>}

View File

@ -33,6 +33,7 @@ export const ITEM_FIELDS = gql`
meForward meForward
outlawed outlawed
freebie freebie
bio
ncomments ncomments
commentSats commentSats
lastCommentAt lastCommentAt

View File

@ -57,6 +57,7 @@ export const MAX_FORWARDS = 5
export const LNURLP_COMMENT_MAX_LENGTH = 1000 export const LNURLP_COMMENT_MAX_LENGTH = 1000
export const RESERVED_MAX_USER_ID = 615 export const RESERVED_MAX_USER_ID = 615
export const GLOBAL_SEED = 616 export const GLOBAL_SEED = 616
export const FREEBIE_BASE_COST_THRESHOLD = 10
export const FOUND_BLURBS = [ 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.', '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.',

View File

@ -10,11 +10,11 @@ import { useMe } from '../../components/me'
import { USER_FULL } from '../../fragments/users' import { USER_FULL } from '../../fragments/users'
import { ITEM_FIELDS } from '../../fragments/items' import { ITEM_FIELDS } from '../../fragments/items'
import { getGetServerSideProps } from '../../api/ssrApollo' import { getGetServerSideProps } from '../../api/ssrApollo'
import FeeButton, { FeeButtonProvider } from '../../components/fee-button' import { FeeButtonProvider } from '../../components/fee-button'
import { bioSchema } from '../../lib/validate' import { bioSchema } from '../../lib/validate'
import CancelButton from '../../components/cancel-button'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import PageLoading from '../../components/page-loading' import PageLoading from '../../components/page-loading'
import { ItemButtonBar } from '../../components/post'
export const getServerSideProps = getGetServerSideProps({ export const getServerSideProps = getGetServerSideProps({
query: USER_FULL, query: USER_FULL,
@ -68,12 +68,7 @@ export function BioForm ({ handleDone, bio }) {
name='bio' name='bio'
minRows={6} minRows={6}
/> />
<div className='d-flex mt-3 justify-content-end'> <ItemButtonBar createText='save' onCancel={handleDone} />
<CancelButton onClick={handleDone} />
<FeeButtonProvider>
<FeeButton text='save' variant='secondary' />
</FeeButtonProvider>
</div>
</Form> </Form>
</FeeButtonProvider> </FeeButtonProvider>
</div> </div>