This commit is contained in:
keyan 2021-09-10 13:55:36 -05:00
parent 3f8b5894cb
commit 0a20f2ea23
8 changed files with 140 additions and 10 deletions

View File

@ -11,13 +11,19 @@ import Markdown from '../svgs/markdown-line.svg'
import styles from './form.module.css'
import Text from '../components/text'
export function SubmitButton ({ children, variant, ...props }) {
const { isSubmitting } = useFormikContext()
export function SubmitButton ({ children, variant, value, onClick, ...props }) {
const { isSubmitting, setFieldValue } = useFormikContext()
return (
<Button
variant={variant || 'main'}
type='submit'
disabled={isSubmitting}
onClick={value
? e => {
setFieldValue('submit', value)
onClick && onClick(e)
}
: onClick}
{...props}
>
{children}
@ -108,7 +114,7 @@ function FormGroup ({ className, label, children }) {
)
}
function InputInner ({ prepend, append, hint, showValid, onChange, overrideValue, ...props }) {
function InputInner ({ prepend, append, hint, showValid, onChange, overrideValue, innerRef, ...props }) {
const [field, meta, helpers] = props.readOnly ? [{}, {}, {}] : useField(props)
const formik = props.readOnly ? null : useFormikContext()
@ -132,6 +138,7 @@ function InputInner ({ prepend, append, hint, showValid, onChange, overrideValue
formik?.submitForm()
}
}}
ref={innerRef}
{...field} {...props}
onChange={(e) => {
field.onChange(e)

102
components/item-act.js Normal file
View File

@ -0,0 +1,102 @@
import { Accordion, 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,
setItem: () => {}
})
export function ItemActProvider ({ children }) {
const [item, setItem] = useState(null)
const contextValue = {
item,
setItem: useCallback(i => setItem(i), [])
}
return (
<ItemActContext.Provider value={contextValue}>
{children}
</ItemActContext.Provider>
)
}
export function useItemAct () {
const { item, setItem } = useContext(ItemActContext)
return { item, setItem }
}
export const ActSchema = Yup.object({
amount: Yup.number().typeError('must be a number').required('required')
.positive('must be positive').integer('must be whole')
})
export function ItemActModal () {
const { item, setItem } = useItemAct()
const [open, setOpen] = useState(false)
const inputRef = useRef(null)
useEffect(() => {
inputRef.current?.focus()
}, [item])
return (
<Modal
show={!!item}
onHide={() => {
setItem(null)
setOpen(false)
}}
>
<Modal.Body>
<Form
initial={{
amount: 21
}}
schema={ActSchema}
onSubmit={async ({ amount, submit }) => {
await item.act({ variables: { id: item.itemId, act: submit, sats: Number(amount) } })
await item.strike()
setOpen(false)
setItem(null)
}}
>
<Input
label='amount'
name='amount'
innerRef={inputRef}
required
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>
<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

@ -39,8 +39,11 @@ export default function Item ({ item, rank, children }) {
<div className={`${styles.other}`}>
<span>{item.sats} sats</span>
<span> \ </span>
<span>{item.boost} boost</span>
<span> \ </span>
{item.boost > 0 &&
<>
<span>{item.boost} boost</span>
<span> \ </span>
</>}
<Link href={`/items/${item.id}`} passHref>
<a className='text-reset'>{item.ncomments} comments</a>
</Link>

View File

@ -5,14 +5,16 @@ import { gql, useMutation } from '@apollo/client'
import { signIn, useSession } from 'next-auth/client'
import { useFundError } from './fund-error'
import ActionTooltip from './action-tooltip'
import { useItemAct } from './item-act'
export default function UpVote ({ itemId, meSats, className }) {
const [session] = useSession()
const { setError } = useFundError()
const { setItem } = useItemAct()
const [act] = useMutation(
gql`
mutation act($id: ID!, $sats: Int!) {
act(id: $id, act: VOTE, sats: $sats)
mutation act($id: ID!, $act: ItemAct! $sats: Int!) {
act(id: $id, act: $act, sats: $sats)
}`, {
update (cache, { data: { act } }) {
// read in the cached object so we don't use meSats prop
@ -59,10 +61,16 @@ export default function UpVote ({ itemId, meSats, className }) {
session
? async (e) => {
e.stopPropagation()
if (meSats >= 1) {
setItem({ itemId, act, strike })
return
}
strike()
if (!itemId) return
try {
await act({ variables: { id: itemId, sats: 1 } })
await act({ variables: { id: itemId, act: 'VOTE', sats: 1 } })
} catch (error) {
if (error.toString().includes('insufficient funds')) {
setError(true)

View File

@ -8,6 +8,7 @@ import { LightningProvider } from '../components/lightning'
import apolloClient from '../lib/apollo'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import { ItemActModal, ItemActProvider } from '../components/item-act'
function MyApp ({ Component, pageProps }) {
const router = useRouter()
@ -30,7 +31,10 @@ function MyApp ({ Component, pageProps }) {
<LightningProvider>
<FundErrorProvider>
<FundErrorModal />
<Component {...pageProps} />
<ItemActProvider>
<ItemActModal />
<Component {...pageProps} />
</ItemActProvider>
</FundErrorProvider>
</LightningProvider>
</MeProvider>

View File

@ -5,7 +5,7 @@ $theme-colors: (
"info" : #007cbe,
"success" : #5c8001,
"twitter" : #1da1f2,
"boost" : #7A0CE9,
"boost" : #8c25f4
);
$body-bg: #f5f5f5;
@ -171,6 +171,10 @@ footer {
fill: #c03221;
}
.text-underline {
text-decoration: underline;
}
@keyframes flash {
from { filter: brightness(1);}
2% { filter: brightness(2.3); }

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 16l-6-6h12z"/></svg>

After

Width:  |  Height:  |  Size: 153 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16 12l-6 6V6z"/></svg>

After

Width:  |  Height:  |  Size: 152 B