Merge pull request #4092 from omnivore-app/feat/web-home-tweaks-02

Implement actions on the home view
This commit is contained in:
Jackson Harper 2024-06-21 13:50:13 +08:00 committed by GitHub
commit 59866510b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 149 additions and 6 deletions

View file

@ -27,6 +27,7 @@ import {
import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives'
import { Toaster } from 'react-hot-toast'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
import useLibraryItemActions from '../../lib/hooks/useLibraryItemActions'
export function HomeContainer(): JSX.Element {
const router = useRouter()
@ -153,6 +154,12 @@ const JustAddedHomeSection = (props: HomeSectionProps): JSX.Element => {
fontSize: '16px',
fontWeight: '600',
color: '$homeTextTitle',
overflow: 'hidden',
textOverflow: 'ellipsis',
wordBreak: 'break-word',
display: '-webkit-box',
'-webkit-line-clamp': '2',
'-webkit-box-orient': 'vertical',
}}
>
{props.homeSection.title}
@ -571,6 +578,8 @@ const TopPicksItemView = (
props: HomeItemViewProps & TopPicksItemViewProps
): JSX.Element => {
const router = useRouter()
const { archiveItem, deleteItem, moveItem } = useLibraryItemActions()
return (
<VStack
css={{
@ -633,7 +642,7 @@ const TopPicksItemView = (
{props.homeItem.canSave && (
<Button
style="homeAction"
onClick={(event) => {
onClick={async (event) => {
event.preventDefault()
event.stopPropagation()
@ -641,6 +650,12 @@ const TopPicksItemView = (
type: 'REMOVE_ITEM',
itemId: props.homeItem.id,
})
if (!(await moveItem(props.homeItem.id))) {
props.dispatchList({
type: 'REPLACE_ITEM',
itemId: props.homeItem.id,
})
}
}}
>
<AddToLibraryActionIcon
@ -651,7 +666,7 @@ const TopPicksItemView = (
{props.homeItem.canArchive && (
<Button
style="homeAction"
onClick={(event) => {
onClick={async (event) => {
event.preventDefault()
event.stopPropagation()
@ -659,6 +674,12 @@ const TopPicksItemView = (
type: 'REMOVE_ITEM',
itemId: props.homeItem.id,
})
if (!(await archiveItem(props.homeItem.id))) {
props.dispatchList({
type: 'REPLACE_ITEM',
itemId: props.homeItem.id,
})
}
}}
>
<ArchiveActionIcon
@ -669,7 +690,7 @@ const TopPicksItemView = (
{props.homeItem.canDelete && (
<Button
style="homeAction"
onClick={(event) => {
onClick={async (event) => {
event.preventDefault()
event.stopPropagation()
@ -677,6 +698,18 @@ const TopPicksItemView = (
type: 'REMOVE_ITEM',
itemId: props.homeItem.id,
})
const undo = () => {
props.dispatchList({
type: 'REPLACE_ITEM',
itemId: props.homeItem.id,
})
}
if (!(await deleteItem(props.homeItem.id, undo))) {
props.dispatchList({
type: 'REPLACE_ITEM',
itemId: props.homeItem.id,
})
}
}}
>
<RemoveActionIcon color={theme.colors.homeActionIcons.toString()} />

View file

@ -416,7 +416,7 @@ const blackThemeSpec = {
const apolloThemeSpec = {
colors: {
readerBg: '#6A6968',
readerBg: '#474747',
readerFont: '#F3F3F3',
readerMargin: '#474747',
readerFontHighContrast: 'white',

View file

@ -0,0 +1,69 @@
import { useState, useEffect, useCallback } from 'react'
import { setLinkArchivedMutation } from '../networking/mutations/setLinkArchivedMutation'
import {
showErrorToast,
showSuccessToast,
showSuccessToastWithUndo,
} from '../toastHelpers'
import { deleteLinkMutation } from '../networking/mutations/deleteLinkMutation'
import { updatePageMutation } from '../networking/mutations/updatePageMutation'
import { State } from '../networking/fragments/articleFragment'
export default function useLibraryItemActions() {
const archiveItem = useCallback(async (itemId: string) => {
const result = await setLinkArchivedMutation({
linkId: itemId,
archived: true,
})
if (result) {
showSuccessToast('Link archived', { position: 'bottom-right' })
} else {
showErrorToast('Error archiving link', { position: 'bottom-right' })
}
return !!result
}, [])
const deleteItem = useCallback(async (itemId: string, undo: () => void) => {
const result = await deleteLinkMutation(itemId)
if (result) {
showSuccessToastWithUndo('Item removed', async () => {
const result = await updatePageMutation({
pageId: itemId,
state: State.SUCCEEDED,
})
undo()
if (result) {
showSuccessToast('Item recovered')
} else {
showErrorToast('Error recovering, check your deleted items')
}
})
} else {
showErrorToast('Error removing item', { position: 'bottom-right' })
}
return !!result
}, [])
const moveItem = useCallback(async (itemId: string) => {
const result = await setLinkArchivedMutation({
linkId: itemId,
archived: true,
})
if (result) {
showSuccessToast('Link archived', { position: 'bottom-right' })
} else {
showErrorToast('Error archiving link', { position: 'bottom-right' })
}
return !!result
}, [])
return { archiveItem, deleteItem, moveItem }
}

View file

@ -0,0 +1,41 @@
import { gql } from 'graphql-request'
import { gqlFetcher } from '../networkHelpers'
type MoveToFolderResponseData = {
success?: boolean
errorCodes?: string[]
}
type MoveToFolderResponse = {
moveToFolder?: MoveToFolderResponseData
}
export async function moveToFolderMutation(
itemId: string,
folder: string
): Promise<boolean> {
const mutation = gql`
mutation MoveToFolder($id: ID!, $folder: String!) {
moveToFolder(id: $id, folder: $folder) {
... on MoveToFolderSuccess {
success
}
... on MoveToFolderError {
errorCodes
}
}
}
`
try {
const response = await gqlFetcher(mutation, { id: itemId, folder })
const data = response as MoveToFolderResponse | undefined
if (data?.moveToFolder?.errorCodes) {
return false
}
return data?.moveToFolder?.success ?? false
} catch (error) {
console.log('MoveToFolder error', error)
return false
}
}

View file

@ -4,10 +4,10 @@ import {
NavigationLayout,
NavigationSection,
} from '../../components/templates/NavigationLayout'
import { HomeContainer } from '../../components/nav-containers/home'
import { HomeContainer } from '../../components/nav-containers/HomeContainer'
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
import { useMemo } from 'react'
import { HighlightsContainer } from '../../components/nav-containers/highlights'
import { HighlightsContainer } from '../../components/nav-containers/HighlightsContainer'
export default function Home(): JSX.Element {
const router = useRouter()