move boost to post creation

This commit is contained in:
keyan 2021-09-11 16:52:19 -05:00
parent 4c7c791ed3
commit 650ad03de5
8 changed files with 114 additions and 56 deletions

View File

@ -113,7 +113,7 @@ export default {
},
Mutation: {
createLink: async (parent, { title, url }, { me, models }) => {
createLink: async (parent, { title, url, boost }, { me, models }) => {
if (!title) {
throw new UserInputError('link must have title', { argumentName: 'title' })
}
@ -122,7 +122,7 @@ export default {
throw new UserInputError('link must have url', { argumentName: 'url' })
}
return await createItem(parent, { title, url: ensureProtocol(url) }, { me, models })
return await createItem(parent, { title, url: ensureProtocol(url), boost }, { me, models })
},
updateLink: async (parent, { id, title, url }, { me, models }) => {
if (!id) {
@ -149,12 +149,12 @@ export default {
return await updateItem(parent, { id, data: { title, url: ensureProtocol(url) } }, { me, models })
},
createDiscussion: async (parent, { title, text }, { me, models }) => {
createDiscussion: async (parent, { title, text, boost }, { me, models }) => {
if (!title) {
throw new UserInputError('discussion must have title', { argumentName: 'title' })
}
return await createItem(parent, { title, text }, { me, models })
return await createItem(parent, { title, text, boost }, { me, models })
},
updateDiscussion: async (parent, { id, title, text }, { me, models }) => {
if (!id) {
@ -407,14 +407,23 @@ const updateItem = async (parent, { id, data }, { me, models }) => {
return item
}
const createItem = async (parent, { title, url, text, parentId }, { me, models }) => {
const createItem = async (parent, { title, url, text, boost, parentId }, { me, models }) => {
if (!me) {
throw new AuthenticationError('you must be logged in')
}
const [item] = await serialize(models, models.$queryRaw(
`${SELECT} FROM create_item($1, $2, $3, $4, $5) AS "Item"`,
title, url, text, Number(parentId), Number(me.id)))
if (boost && boost < 0) {
throw new UserInputError('boost must be positive', { argumentName: 'boost' })
}
const [item] = await serialize(models,
models.$queryRaw(`${SELECT} FROM create_item($1, $2, $3, $4, $5) AS "Item"`,
title, url, text, Number(parentId), Number(me.id)))
if (boost) {
await serialize(models,
models.$queryRaw`SELECT item_act(${item.id}, ${me.id}, 'BOOST', ${Number(boost)})`)
}
await createMentions(item, models)

View File

@ -21,9 +21,9 @@ export default gql`
}
extend type Mutation {
createLink(title: String!, url: String): Item!
createLink(title: String!, url: String, boost: Int): Item!
updateLink(id: ID!, title: String!, url: String): Item!
createDiscussion(title: String!, text: String): Item!
createDiscussion(title: String!, text: String, boost: Int): Item!
updateDiscussion(id: ID!, title: String!, text: String): Item!
createComment(text: String!, parentId: ID!): Item!
updateComment(id: ID!, text: String!): Item!

View File

@ -0,0 +1,31 @@
import { Accordion } from 'react-bootstrap'
import ArrowRight from '../svgs/arrow-right-s-fill.svg'
import ArrowDown from '../svgs/arrow-down-s-fill.svg'
import { useEffect, useState } from 'react'
export default function AccordianItem ({ header, body, headerColor = 'grey' }) {
const [open, setOpen] = useState(false)
useEffect(() => {
setOpen(false)
}, [])
return (
<Accordion>
<Accordion.Toggle
as={props => <div {...props} />}
eventKey='0'
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}
onClick={() => setOpen(!open)}
>
{open
? <ArrowDown style={{ fill: headerColor }} height={20} width={20} />
: <ArrowRight style={{ fill: headerColor }} height={20} width={20} />}
<div style={{ color: headerColor }}>{header}</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey='0' className='mt-2'>
<div>{body}</div>
</Accordion.Collapse>
</Accordion>
)
}

View File

@ -0,0 +1,29 @@
import AccordianItem from './accordian-item'
import * as Yup from 'yup'
import { Input } from './form'
import { InputGroup } from 'react-bootstrap'
export const AdvPostSchema = {
boost: Yup.number().typeError('must be a number')
.min(0, 'must be positive').integer('must be whole')
}
export const AdvPostInitial = {
boost: 0
}
export default function AdvPostForm () {
return (
<AccordianItem
header={<div className='font-weight-bold'>advanced</div>}
body={
<Input
label='boost'
name='boost'
hint={<span className='text-muted'>boost ranks posts higher temporarily depending on the amount</span>}
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
/>
}
/>
)
}

View File

@ -5,17 +5,19 @@ import { gql, useMutation } from '@apollo/client'
import ActionTooltip from '../components/action-tooltip'
import TextareaAutosize from 'react-textarea-autosize'
import Countdown from './countdown'
import AdvPostForm, { AdvPostInitial, AdvPostSchema } from './adv-post-form'
export const DiscussionSchema = Yup.object({
title: Yup.string().required('required').trim()
title: Yup.string().required('required').trim(),
...AdvPostSchema
})
export function DiscussionForm ({ item, editThreshold }) {
const router = useRouter()
const [createDiscussion] = useMutation(
gql`
mutation createDiscussion($title: String!, $text: String) {
createDiscussion(title: $title, text: $text) {
mutation createDiscussion($title: String!, $text: String, $boost: Int) {
createDiscussion(title: $title, text: $text, boost: $boost) {
id
}
}`
@ -47,15 +49,16 @@ export function DiscussionForm ({ item, editThreshold }) {
<Form
initial={{
title: item?.title || '',
text: item?.text || ''
text: item?.text || '',
...AdvPostInitial
}}
schema={DiscussionSchema}
onSubmit={async (values) => {
onSubmit={async ({ boost, ...values }) => {
let id, error
if (item) {
({ data: { updateDiscussion: { id } }, error } = await updateDiscussion({ variables: { ...values, id: item.id } }))
} else {
({ data: { createDiscussion: { id } }, error } = await createDiscussion({ variables: values }))
({ data: { createDiscussion: { id } }, error } = await createDiscussion({ variables: { boost: Number(boost), ...values } }))
}
if (error) {
throw new Error({ message: error.toString() })
@ -78,9 +81,12 @@ export function DiscussionForm ({ item, editThreshold }) {
? <Countdown date={editThreshold} />
: null}
/>
<ActionTooltip>
<SubmitButton variant='secondary' className='mt-2'>{item ? 'save' : 'post'}</SubmitButton>
</ActionTooltip>
{!item && <AdvPostForm />}
<div className='d-flex'>
<ActionTooltip>
<SubmitButton variant='secondary' className='mt-2 ml-auto'>{item ? 'save' : 'post'}</SubmitButton>
</ActionTooltip>
</div>
</Form>
)
}

View File

@ -1,9 +1,7 @@
import { Accordion, InputGroup, Modal } from 'react-bootstrap'
import { InputGroup, Modal } from 'react-bootstrap'
import React, { useState, useCallback, useContext, useRef, useEffect } from 'react'
import * as Yup from 'yup'
import { Form, Input, SubmitButton } from './form'
import ArrowRight from '../svgs/arrow-right-s-fill.svg'
import ArrowDown from '../svgs/arrow-down-s-fill.svg'
export const ItemActContext = React.createContext({
item: null,
@ -37,7 +35,6 @@ export const ActSchema = Yup.object({
export function ItemActModal () {
const { item, setItem } = useItemAct()
const [open, setOpen] = useState(false)
const inputRef = useRef(null)
useEffect(() => {
@ -49,7 +46,6 @@ export function ItemActModal () {
show={!!item}
onHide={() => {
setItem(null)
setOpen(false)
}}
>
<Modal.Body>
@ -61,7 +57,6 @@ export function ItemActModal () {
onSubmit={async ({ amount, submit }) => {
await item.act({ variables: { id: item.itemId, act: submit, sats: Number(amount) } })
await item.strike()
setOpen(false)
setItem(null)
}}
>
@ -73,28 +68,9 @@ export function ItemActModal () {
autoFocus
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
/>
<div className='d-flex justify-content-between'>
<SubmitButton variant='boost' className='mt-1' value='BOOST'>boost</SubmitButton>
<SubmitButton variant='success' className='mt-1 px-4' value='TIP'>tip</SubmitButton>
<div className='d-flex'>
<SubmitButton variant='success' className='ml-auto mt-1 px-4' value='TIP'>tip</SubmitButton>
</div>
<Accordion className='pt-3'>
<Accordion.Toggle
as={props => <div {...props} />}
eventKey='0'
style={{ cursor: 'pointer', display: 'flex', justifyContent: 'center', alignItems: 'center' }}
onClick={() => setOpen(!open)}
>
{open
? <ArrowDown className='fill-grey' height={16} width={16} />
: <ArrowRight className='fill-grey' height={16} width={16} />}
<small className='text-muted text-underline'>I'm confused</small>
</Accordion.Toggle>
<Accordion.Collapse eventKey='0' className='mt-2'>
<span>Tips go directly to the poster or commenter. Boosts boost the rank
of the post or comment for a limited time, and the sats go to the site.
</span>
</Accordion.Collapse>
</Accordion>
</Form>
</Modal.Body>
</Modal>

View File

@ -17,7 +17,7 @@
}
a.link:visited {
color: grey;
color: #7acaf5;
}
.other {

View File

@ -5,6 +5,7 @@ import { gql, useLazyQuery, useMutation } from '@apollo/client'
import { ensureProtocol } from '../lib/url'
import ActionTooltip from '../components/action-tooltip'
import Countdown from './countdown'
import AdvPostForm, { AdvPostInitial, AdvPostSchema } from './adv-post-form'
export const LinkSchema = Yup.object({
title: Yup.string().required('required').trim(),
@ -20,7 +21,8 @@ export const LinkSchema = Yup.object({
}
},
message: 'invalid url'
}).required('required')
}).required('required'),
...AdvPostSchema
})
export function LinkForm ({ item, editThreshold }) {
@ -31,8 +33,8 @@ export function LinkForm ({ item, editThreshold }) {
const router = useRouter()
const [createLink] = useMutation(
gql`
mutation createLink($title: String!, $url: String!) {
createLink(title: $title, url: $url) {
mutation createLink($title: String!, $url: String!, $boost: Int) {
createLink(title: $title, url: $url, boost: $boost) {
id
}
}`
@ -66,15 +68,16 @@ export function LinkForm ({ item, editThreshold }) {
<Form
initial={{
title: item?.title || '',
url: item?.url || ''
url: item?.url || '',
...AdvPostInitial
}}
schema={LinkSchema}
onSubmit={async (values) => {
onSubmit={async ({ boost, ...values }) => {
let id, error
if (item) {
({ data: { updateLink: { id } }, error } = await updateLink({ variables: { ...values, id: item.id } }))
} else {
({ data: { createLink: { id } }, error } = await createLink({ variables: values }))
({ data: { createLink: { id } }, error } = await createLink({ variables: { boost: Number(boost), ...values } }))
}
if (error) {
throw new Error({ message: error.toString() })
@ -104,9 +107,13 @@ export function LinkForm ({ item, editThreshold }) {
}
}}
/>
<ActionTooltip>
<SubmitButton variant='secondary' className='mt-2'>{item ? 'save' : 'post'}</SubmitButton>
</ActionTooltip>
{!item && <AdvPostForm />}
<div className='d-flex'>
<ActionTooltip>
<SubmitButton variant='secondary' className='mt-2 ml-auto'>{item ? 'save' : 'post'}</SubmitButton>
</ActionTooltip>
</div>
</Form>
)
}