Mark images as submitted on client after successful mutation

This commit is contained in:
ekzyis 2023-10-19 18:16:25 +02:00 committed by ekzyis
parent f79792cd4d
commit 086e1aea3a
8 changed files with 66 additions and 6 deletions

View File

@ -12,6 +12,7 @@ import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me'
import { useImages } from './image'
export function BountyForm ({
item,
@ -27,6 +28,7 @@ export function BountyForm ({
const router = useRouter()
const client = useApolloClient()
const me = useMe()
const { markImagesAsSubmitted } = useImages()
const schema = bountySchema({ client, me, existingBoost: item?.boost })
const [upsertBounty] = useMutation(
gql`
@ -55,7 +57,11 @@ export function BountyForm ({
id
}
}
`
`, {
onCompleted ({ upsertBounty: { text } }) {
markImagesAsSubmitted(text)
}
}
)
const onSubmit = useCallback(

View File

@ -5,8 +5,10 @@ import { EditFeeButton } from './fee-button'
import Button from 'react-bootstrap/Button'
import Delete from './delete'
import { commentSchema } from '../lib/validate'
import { useImages } from './image'
export default function CommentEdit ({ comment, editThreshold, onSuccess, onCancel }) {
const { markImagesAsSubmitted } = useImages()
const [upsertComment] = useMutation(
gql`
mutation upsertComment($id: ID! $text: String!) {
@ -14,6 +16,9 @@ export default function CommentEdit ({ comment, editThreshold, onSuccess, onCanc
text
}
}`, {
onCompleted ({ upsertComment: { text } }) {
markImagesAsSubmitted(text)
},
update (cache, { data: { upsertComment } }) {
cache.modify({
id: `Item:${comment.id}`,

View File

@ -17,6 +17,7 @@ import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me'
import useCrossposter from './use-crossposter'
import { useImages } from './image'
export function DiscussionForm ({
item, sub, editThreshold, titleLabel = 'title',
@ -30,14 +31,21 @@ export function DiscussionForm ({
// if Web Share Target API was used
const shareTitle = router.query.title
const crossposter = useCrossposter()
const { markImagesAsSubmitted } = useImages()
const [upsertDiscussion] = useMutation(
gql`
mutation upsertDiscussion($sub: String, $id: ID, $title: String!, $text: String, $boost: Int, $forward: [ItemForwardInput], $hash: String, $hmac: String) {
upsertDiscussion(sub: $sub, id: $id, title: $title, text: $text, boost: $boost, forward: $forward, hash: $hash, hmac: $hmac) {
id
text
}
}`,
{
onCompleted ({ upsertDiscussion: { text } }) {
markImagesAsSubmitted(text)
}
}
}`
)
const onSubmit = useCallback(

View File

@ -8,6 +8,7 @@ import { UPLOAD_TYPES_ALLOW } from '../lib/constants'
import { useToast } from './toast'
import gql from 'graphql-tag'
import { useMutation, useQuery } from '@apollo/client'
import { extractUrls } from '../lib/md'
const ImageContext = createContext({ unsubmitted: [] })
@ -44,6 +45,18 @@ export function ImageProvider ({ me, children }) {
})
const [unsubmittedImages, setUnsubmittedImages] = useState([])
const markImagesAsSubmitted = useCallback((text) => {
// mark images from S3 included in the text as submitted on the client
const urls = extractUrls(text)
const s3UrlPrefix = `https://${process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET}.s3.amazonaws.com/`
urls
.filter(url => url.startsWith(s3UrlPrefix))
.forEach(url => {
const s3Key = url.split('/').pop()
setUnsubmittedImages(prev => prev.filter(img => img.id !== s3Key))
})
}, [setUnsubmittedImages])
useEffect(() => {
const images = data?.me?.images
if (images) {
@ -54,7 +67,8 @@ export function ImageProvider ({ me, children }) {
const contextValue = {
unsubmittedImages,
setUnsubmittedImages,
deleteImage
deleteImage,
markImagesAsSubmitted
}
return (

View File

@ -18,6 +18,7 @@ import ActionTooltip from './action-tooltip'
import { jobSchema } from '../lib/validate'
import CancelButton from './cancel-button'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useImages } from './image'
function satsMin2Mo (minute) {
return minute * 30 * 24 * 60
@ -40,6 +41,7 @@ export default function JobForm ({ item, sub }) {
const storageKeyPrefix = item ? undefined : `${sub.name}-job`
const router = useRouter()
const [logoId, setLogoId] = useState(item?.uploadId)
const { markImagesAsSubmitted } = useImages()
const [upsertJob] = useMutation(gql`
mutation upsertJob($sub: String!, $id: ID, $title: String!, $company: String!, $location: String,
$remote: Boolean, $text: String!, $url: String!, $maxBid: Int!, $status: String, $logo: Int, $hash: String, $hmac: String) {
@ -47,8 +49,13 @@ export default function JobForm ({ item, sub }) {
location: $location, remote: $remote, text: $text,
url: $url, maxBid: $maxBid, status: $status, logo: $logo, hash: $hash, hmac: $hmac) {
id
text
}
}`, {
onCompleted ({ upsertJob: { text } }) {
markImagesAsSubmitted(text)
}
}
}`
)
const onSubmit = useCallback(

View File

@ -17,6 +17,7 @@ import CancelButton from './cancel-button'
import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me'
import { useImages } from './image'
export function LinkForm ({ item, sub, editThreshold, children }) {
const router = useRouter()
@ -52,6 +53,7 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
}
}
}`)
const { markImagesAsSubmitted } = useImages
const related = []
for (const item of relatedData?.related?.items || []) {
@ -73,8 +75,14 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
mutation upsertLink($sub: String, $id: ID, $title: String!, $url: String!, $text: String, $boost: Int, $forward: [ItemForwardInput], $hash: String, $hmac: String) {
upsertLink(sub: $sub, id: $id, title: $title, url: $url, text: $text, boost: $boost, forward: $forward, hash: $hash, hmac: $hmac) {
id
text
}
}`,
{
onCompleted ({ upsertLink: { text } }) {
markImagesAsSubmitted(text)
}
}
}`
)
const onSubmit = useCallback(

View File

@ -13,12 +13,14 @@ import CancelButton from './cancel-button'
import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form'
import { useMe } from './me'
import { useImages } from './image'
export function PollForm ({ item, sub, editThreshold, children }) {
const router = useRouter()
const client = useApolloClient()
const me = useMe()
const schema = pollSchema({ client, me, existingBoost: item?.boost })
const { markImagesAsSubmitted } = useImages()
const [upsertPoll] = useMutation(
gql`
@ -27,8 +29,13 @@ export function PollForm ({ item, sub, editThreshold, children }) {
upsertPoll(sub: $sub, id: $id, title: $title, text: $text,
options: $options, boost: $boost, forward: $forward, hash: $hash, hmac: $hmac) {
id
text
}
}`, {
onCompleted ({ upsertPoll: { text } }) {
markImagesAsSubmitted(text)
}
}
}`
)
const onSubmit = useCallback(

View File

@ -11,6 +11,7 @@ import { commentSchema } from '../lib/validate'
import Info from './info'
import { quote } from '../lib/md'
import { COMMENT_DEPTH_LIMIT } from '../lib/constants'
import { useImages } from './image'
export function ReplyOnAnotherPage ({ item }) {
const path = item.path.split('.')
@ -49,6 +50,7 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
const parentId = item.id
const replyInput = useRef(null)
const formInnerRef = useRef()
const { markImagesAsSubmitted } = useImages()
// Start block to handle iOS Safari's weird selection clearing behavior
const savedRange = useRef()
@ -116,6 +118,9 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
}
}
}`, {
onCompleted ({ upsertComment: { text } }) {
markImagesAsSubmitted(text)
},
update (cache, { data: { upsertComment } }) {
cache.modify({
id: `Item:${parentId}`,