move boost to post creation
This commit is contained in:
parent
4c7c791ed3
commit
650ad03de5
|
@ -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)
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -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>}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
}
|
||||
|
||||
a.link:visited {
|
||||
color: grey;
|
||||
color: #7acaf5;
|
||||
}
|
||||
|
||||
.other {
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue