account for job payment status

This commit is contained in:
keyan 2022-02-26 10:41:30 -06:00
parent 1338c026a3
commit bc1c45e7bf
7 changed files with 115 additions and 13 deletions

View File

@ -81,6 +81,10 @@ export default {
return sub ? ` AND "subName" = $${num} ` : ` AND ("subName" IS NULL OR "subName" = $${3}) `
}
const activeOrMine = () => {
return me ? ` AND (status = 'ACTIVE' OR "userId" = ${me.id}) ` : ' AND status = \'ACTIVE\' '
}
switch (sort) {
case 'user':
if (!name) {
@ -97,6 +101,7 @@ export default {
FROM "Item"
WHERE "userId" = $1 AND "parentId" IS NULL AND created_at <= $2
AND "pinId" IS NULL
${activeOrMine()}
ORDER BY created_at DESC
OFFSET $3
LIMIT ${LIMIT}`, user.id, decodedCursor.time, decodedCursor.offset)
@ -107,6 +112,7 @@ export default {
FROM "Item"
WHERE "parentId" IS NULL AND created_at <= $1 AND "pinId" IS NULL
${subClause(3)}
${activeOrMine()}
ORDER BY created_at DESC
OFFSET $2
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset, sub || 'NULL')
@ -140,6 +146,7 @@ export default {
WHERE "parentId" IS NULL AND created_at <= $1
AND "pinId" IS NULL
${subClause(3)}
AND status = 'ACTIVE'
ORDER BY "maxBid" / 1000 DESC, created_at ASC
OFFSET $2
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset, sub)
@ -291,7 +298,7 @@ export default {
comments: async (parent, { id, sort }, { models }) => {
return comments(models, id, sort)
},
search: async (parent, { q: query, sub, cursor }, { models, search }) => {
search: async (parent, { q: query, sub, cursor }, { me, models, search }) => {
const decodedCursor = decodeCursor(cursor)
let sitems
@ -305,8 +312,18 @@ export default {
bool: {
must: [
sub
? { term: { 'sub.name': sub } }
? { match: { 'sub.name': sub } }
: { bool: { must_not: { exists: { field: 'sub.name' } } } },
me
? {
bool: {
should: [
{ match: { status: 'ACTIVE' } },
{ match: { userId: me.id } }
]
}
}
: { match: { status: 'ACTIVE' } },
{
bool: {
should: [
@ -395,6 +412,7 @@ export default {
const where = {
where: {
subName: sub,
status: 'ACTIVE',
OR: [{
maxBid: {
gte: bid + 1000
@ -487,7 +505,7 @@ export default {
return await updateItem(parent, { id, data: { title, text } }, { me, models })
},
upsertJob: async (parent, { id, sub, title, text, url, maxBid }, { me, models }) => {
upsertJob: async (parent, { id, sub, title, text, url, maxBid, status }, { me, models }) => {
if (!me) {
throw new AuthenticationError('you must be logged in to create job')
}
@ -512,6 +530,15 @@ export default {
throw new UserInputError(`bid must be at least ${fullSub.baseCost}`, { argumentName: 'maxBid' })
}
const checkSats = async () => {
// check if the user has the funds to run for the first minute
const minuteMsats = maxBid * 1000 / 30 / 24 / 60
const user = models.user.findUnique({ where: { id: me.id } })
if (user.msats < minuteMsats) {
throw new UserInputError('insufficient funds')
}
}
const data = {
title,
text,
@ -522,12 +549,23 @@ export default {
}
if (id) {
if (status) {
data.status = status
// if the job is changing to active, we need to check they have funds
if (status === 'ACTIVE') {
await checkSats()
}
}
return await models.item.update({
where: { id: Number(id) },
data
})
}
// before creating job, check the sats
await checkSats()
return await models.item.create({
data
})
@ -850,7 +888,7 @@ function nestComments (flat, parentId) {
export const SELECT =
`SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
"Item".text, "Item".url, "Item"."userId", "Item"."parentId", "Item"."pinId", "Item"."maxBid",
"Item"."subName", ltree2text("Item"."path") AS "path"`
"Item"."subName", "Item".status, ltree2text("Item"."path") AS "path"`
const LEFT_JOIN_SATS_SELECT = 'SELECT i.id, SUM(CASE WHEN "ItemAct".act = \'VOTE\' THEN "ItemAct".sats ELSE 0 END) as sats, SUM(CASE WHEN "ItemAct".act = \'BOOST\' THEN "ItemAct".sats ELSE 0 END) as boost'

View File

@ -25,7 +25,7 @@ export default gql`
updateDiscussion(id: ID!, title: String!, text: String): Item!
createComment(text: String!, parentId: ID!): Item!
updateComment(id: ID!, text: String!): Item!
upsertJob(id: ID, sub: ID!, title: String!, text: String!, url: String!, maxBid: Int!): Item!
upsertJob(id: ID, sub: ID!, title: String!, text: String!, url: String!, maxBid: Int!, status: String): Item!
act(id: ID!, sats: Int): ItemActResult!
}
@ -67,5 +67,6 @@ export default gql`
prior: Int
maxBid: Int
sub: Sub
status: String
}
`

View File

@ -69,6 +69,7 @@ export function ItemJob ({ item, rank, children }) {
edit
</a>
</Link>
{item.status !== 'ACTIVE' && <span className='font-weight-bold text-danger'> {item.status}</span>}
</>}
</div>
</div>

View File

@ -24,7 +24,6 @@
.case {
fill: #a5a5a5;
margin-right: .2rem;
margin-left: .2rem;
margin-top: .2rem;
padding: 0 2px;
}

View File

@ -1,4 +1,4 @@
import { Form, Input, MarkdownInput, SubmitButton } from './form'
import { Checkbox, Form, Input, MarkdownInput, SubmitButton } from './form'
import TextareaAutosize from 'react-textarea-autosize'
import { InputGroup, Modal } from 'react-bootstrap'
import * as Yup from 'yup'
@ -8,6 +8,7 @@ import AccordianItem from './accordian-item'
import styles from '../styles/post.module.css'
import { useLazyQuery, gql, useMutation } from '@apollo/client'
import { useRouter } from 'next/router'
import Link from 'next/link'
Yup.addMethod(Yup.string, 'or', function (schemas, msg) {
return this.test({
@ -41,8 +42,10 @@ export default function JobForm ({ item, sub }) {
}`,
{ fetchPolicy: 'network-only' })
const [upsertJob] = useMutation(gql`
mutation upsertJob($id: ID, $title: String!, $text: String!, $url: String!, $maxBid: Int!) {
upsertJob(sub: "${sub.name}", id: $id title: $title, text: $text, url: $url, maxBid: $maxBid) {
mutation upsertJob($id: ID, $title: String!, $text: String!,
$url: String!, $maxBid: Int!, $status: String) {
upsertJob(sub: "${sub.name}", id: $id title: $title, text: $text,
url: $url, maxBid: $maxBid, status: $status) {
id
}
}`
@ -118,12 +121,21 @@ export default function JobForm ({ item, sub }) {
title: item?.title || '',
text: item?.text || '',
url: item?.url || '',
maxBid: item?.maxBid || sub.baseCost
maxBid: item?.maxBid || sub.baseCost,
stop: false,
start: false
}}
schema={JobSchema}
storageKeyPrefix={storageKeyPrefix}
onSubmit={(async ({ maxBid, ...values }) => {
const variables = { sub: sub.name, maxBid: Number(maxBid), ...values }
onSubmit={(async ({ maxBid, stop, start, ...values }) => {
let status
if (start) {
status = 'ACTIVE'
} else if (stop) {
status = 'STOPPED'
}
const variables = { sub: sub.name, maxBid: Number(maxBid), status, ...values }
if (item) {
variables.id = item.id
}
@ -176,8 +188,57 @@ export default function JobForm ({ item, sub }) {
hint={<span className='text-muted'>up to {pull} sats/min will be pulled from your wallet</span>}
/>
<div className='font-weight-bold text-muted'>This bid puts your job in position: {position}</div>
{item && <StatusControl item={item} />}
<SubmitButton variant='secondary' className='mt-3'>{item ? 'save' : 'post'}</SubmitButton>
</Form>
</>
)
}
function StatusControl ({ item }) {
let StatusComp
if (item.status === 'ACTIVE') {
StatusComp = () => {
return (
<AccordianItem
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>I want to stop my job</div>}
headerColor='var(--danger)'
body={
<Checkbox
label={<div className='font-weight-bold text-danger'>stop my job</div>} name='stop' inline
/>
}
/>
)
}
} else if (item.status === 'STOPPED') {
StatusComp = () => {
return (
<AccordianItem
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>I want to resume my job</div>}
headerColor='var(--success)'
body={
<Checkbox
label={<div className='font-weight-bold text-success'>resume my job</div>} name='start' inline
/>
}
/>
)
}
} else {
StatusComp = () => {
return (
<div style={{ fontWeight: 'bold', color: 'var(--danger)' }}>
you have no sats! <Link href='/wallet?type=fund' passHref><a className='text-reset text-underline'>fund your wallet</a></Link> to resume your job
</div>
)
}
}
return (
<div className='my-2'>
<StatusComp />
</div>
)
}

View File

@ -22,6 +22,7 @@ export const ITEM_FIELDS = gql`
name
baseCost
}
status
mine
root {
id

View File

@ -17,6 +17,7 @@ const ITEM_SEARCH_FIELDS = gql`
sub {
name
}
status
maxBid
upvotes
sats