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