| @@ -11,10 +11,11 @@ type Props = { posts: Post[] | |||||
| export default (({ posts, onClick }: Props) => ( | export default (({ posts, onClick }: Props) => ( | ||||
| <div className="flex flex-wrap gap-6 p-4"> | <div className="flex flex-wrap gap-6 p-4"> | ||||
| {posts.map ((post, i) => ( | {posts.map ((post, i) => ( | ||||
| <PrefetchLink to={`/posts/${ post.id }`} | |||||
| key={post.id} | |||||
| className="w-40 h-40 overflow-hidden rounded-lg shadow-md hover:shadow-lg" | |||||
| onClick={onClick}> | |||||
| <PrefetchLink | |||||
| to={`/posts/${ post.id }`} | |||||
| key={post.id} | |||||
| className="w-40 h-40 overflow-hidden rounded-lg shadow-md hover:shadow-lg" | |||||
| onClick={onClick}> | |||||
| <img src={post.thumbnail || post.thumbnailBase || undefined} | <img src={post.thumbnail || post.thumbnailBase || undefined} | ||||
| alt={post.title || post.url} | alt={post.title || post.url} | ||||
| title={post.title || post.url || undefined} | title={post.title || post.url || undefined} | ||||
| @@ -16,13 +16,13 @@ type Props = AnchorHTMLAttributes<HTMLAnchorElement> & { | |||||
| export default (({ to, | export default (({ to, | ||||
| replace, | |||||
| className, | |||||
| onMouseEnter, | |||||
| onTouchStart, | |||||
| onClick, | |||||
| cancelOnError = false, | |||||
| ...rest }: Props) => { | |||||
| replace, | |||||
| className, | |||||
| onMouseEnter, | |||||
| onTouchStart, | |||||
| onClick, | |||||
| cancelOnError = false, | |||||
| ...rest }: Props) => { | |||||
| const navigate = useNavigate () | const navigate = useNavigate () | ||||
| const qc = useQueryClient () | const qc = useQueryClient () | ||||
| const url = useMemo (() => (new URL (to, location.origin)).toString (), [to]) | const url = useMemo (() => (new URL (to, location.origin)).toString (), [to]) | ||||
| @@ -43,19 +43,19 @@ export default (({ user }: Props) => { | |||||
| return next | return next | ||||
| }, | }, | ||||
| onMutate: async () => { | onMutate: async () => { | ||||
| await qc.cancelQueries ({ queryKey: ['post', String (id)] }) | |||||
| const prev = qc.getQueryData<any> (['post', String (id)]) | |||||
| qc.setQueryData (['post', String (id)], | |||||
| await qc.cancelQueries ({ queryKey: ['posts', String (id)] }) | |||||
| const prev = qc.getQueryData<any> (['posts', String (id)]) | |||||
| qc.setQueryData (['posts', String (id)], | |||||
| (cur: any) => cur ? { ...cur, viewed: !(cur.viewed) } : cur) | (cur: any) => cur ? { ...cur, viewed: !(cur.viewed) } : cur) | ||||
| return { prev } | return { prev } | ||||
| }, | }, | ||||
| onError: (...[, , ctx]) => { | onError: (...[, , ctx]) => { | ||||
| if (ctx?.prev) | if (ctx?.prev) | ||||
| qc.setQueryData (['post', String (id)], ctx.prev) | |||||
| qc.setQueryData (['posts', String (id)], ctx.prev) | |||||
| toast ({ title: '失敗……', description: '通信に失敗しました……' }) | toast ({ title: '失敗……', description: '通信に失敗しました……' }) | ||||
| }, | }, | ||||
| onSuccess: () => { | onSuccess: () => { | ||||
| qc.invalidateQueries ({ queryKey: ['posts'] }) | |||||
| qc.invalidateQueries ({ queryKey: ['posts', 'index'] }) | |||||
| qc.invalidateQueries ({ queryKey: ['related', String (id)] }) | qc.invalidateQueries ({ queryKey: ['related', String (id)] }) | ||||
| } }) | } }) | ||||