WIP tips
This commit is contained in:
parent
3f8b5894cb
commit
0a20f2ea23
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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 |
|
@ -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 |
Loading…
Reference in New Issue