mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
270 lines
7.9 KiB
TypeScript
270 lines
7.9 KiB
TypeScript
import { useMemo, useState } from 'react'
|
|
import { applyStoredTheme } from '../../../lib/themeUpdater'
|
|
|
|
import {
|
|
EmptySettingsRow,
|
|
SettingsTable,
|
|
SettingsTableRow,
|
|
} from '../../../components/templates/settings/SettingsTable'
|
|
import { StyledText } from '../../../components/elements/StyledText'
|
|
import {
|
|
RecentEmail,
|
|
useGetRecentEmailsQuery,
|
|
} from '../../../lib/networking/queries/useGetRecentEmails'
|
|
import {
|
|
Box,
|
|
HStack,
|
|
SpanBox,
|
|
VStack,
|
|
} from '../../../components/elements/LayoutPrimitives'
|
|
import { DropdownOption } from '../../../components/elements/DropdownElements'
|
|
import { theme } from '../../../components/tokens/stitches.config'
|
|
import {
|
|
ModalContent,
|
|
ModalOverlay,
|
|
ModalRoot,
|
|
ModalTitleBar,
|
|
} from '../../../components/elements/ModalPrimitives'
|
|
import { markEmailAsItemMutation } from '../../../lib/networking/mutations/markEmailAsItemMutation'
|
|
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
|
|
|
|
type TypeChipProps = {
|
|
type: string
|
|
}
|
|
|
|
const TypeChip = (props: TypeChipProps): JSX.Element => {
|
|
const backgroundColor = props.type == 'article' ? '$omnivoreCtaYellow' : 'red'
|
|
return (
|
|
<SpanBox
|
|
css={{
|
|
color: 'black',
|
|
display: 'inline-table',
|
|
marginTop: '5px',
|
|
borderRadius: '4px',
|
|
fontSize: '14px',
|
|
fontWeight: 'bold',
|
|
padding: '5px 10px 5px 10px',
|
|
whiteSpace: 'nowrap',
|
|
cursor: 'pointer',
|
|
backgroundClip: 'padding-box',
|
|
backgroundColor,
|
|
}}
|
|
>
|
|
{props.type}
|
|
</SpanBox>
|
|
)
|
|
}
|
|
|
|
type MoreOptionItemProps = {
|
|
text: string
|
|
action: () => void
|
|
}
|
|
|
|
const MoreOptionItem = (props: MoreOptionItemProps): JSX.Element => {
|
|
return (
|
|
<DropdownOption
|
|
onSelect={() => {
|
|
props.action()
|
|
}}
|
|
>
|
|
<HStack alignment={'center'} distribution={'start'}>
|
|
<SpanBox
|
|
css={{
|
|
color: theme.colors.grayTextContrast.toString(),
|
|
marginLeft: '8px',
|
|
border: 'none',
|
|
backgroundColor: 'transparent',
|
|
'&:hover': {
|
|
border: 'none',
|
|
backgroundColor: 'transparent',
|
|
},
|
|
}}
|
|
>
|
|
{props.text}
|
|
</SpanBox>
|
|
</HStack>
|
|
</DropdownOption>
|
|
)
|
|
}
|
|
|
|
type ViewRecentEmailModalProps = {
|
|
display: 'html' | 'text'
|
|
recentEmail: RecentEmail
|
|
onOpenChange: (open: boolean) => void
|
|
}
|
|
|
|
const ViewRecentEmailModal = (
|
|
props: ViewRecentEmailModalProps
|
|
): JSX.Element => {
|
|
return (
|
|
<ModalRoot defaultOpen onOpenChange={props.onOpenChange}>
|
|
<ModalOverlay />
|
|
<ModalContent
|
|
css={{
|
|
bg: '$grayBg',
|
|
px: '24px',
|
|
overflowY: 'auto',
|
|
height: '100%',
|
|
width: '100%',
|
|
maxWidth: '650px',
|
|
}}
|
|
onInteractOutside={() => {
|
|
// remove focus from modal
|
|
;(document.activeElement as HTMLElement).blur()
|
|
}}
|
|
>
|
|
<VStack distribution="start" css={{ height: '100%' }}>
|
|
<ModalTitleBar title="View Email" onOpenChange={props.onOpenChange} />
|
|
{props.display == 'text' ? (
|
|
<Box
|
|
css={{
|
|
width: '100%',
|
|
height: '100%',
|
|
fontSize: '12px',
|
|
overflowY: 'scroll',
|
|
}}
|
|
>
|
|
{props.recentEmail.text}
|
|
</Box>
|
|
) : (
|
|
<Box
|
|
css={{
|
|
width: '100%',
|
|
height: '100%',
|
|
fontSize: '12px',
|
|
overflowY: 'scroll',
|
|
iframe: {
|
|
width: '100%',
|
|
height: '100%',
|
|
display: 'block',
|
|
border: 'none',
|
|
},
|
|
}}
|
|
>
|
|
<iframe srcDoc={props.recentEmail.html}></iframe>
|
|
</Box>
|
|
)}
|
|
</VStack>
|
|
</ModalContent>
|
|
</ModalRoot>
|
|
)
|
|
}
|
|
|
|
export default function RecentEmails(): JSX.Element {
|
|
const { recentEmails, revalidate, isValidating } = useGetRecentEmailsQuery()
|
|
const [viewingEmailText, setViewingEmailText] = useState<
|
|
RecentEmail | undefined
|
|
>(undefined)
|
|
|
|
const [viewingEmailHtml, setViewingEmailHtml] = useState<
|
|
RecentEmail | undefined
|
|
>(undefined)
|
|
|
|
applyStoredTheme(false)
|
|
|
|
const sortedRecentEmails = useMemo(() => {
|
|
return recentEmails.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
|
|
}, [recentEmails])
|
|
|
|
return (
|
|
<SettingsTable
|
|
pageId="recent-emails"
|
|
pageInfoLink="https://docs.omnivore.app/using/inbox.html"
|
|
headerTitle="Recently Received Emails"
|
|
suggestionInfo={{
|
|
title:
|
|
'View original emails that have been recently received in your Omnivore inbox.',
|
|
message:
|
|
"Your 30 most recent emails are stored below. You can click on each email to view its original content or it's text content. If an email was not correctly classified as an article you can mark it as an article and it will be added to your library.",
|
|
docs: 'https://docs.omnivore.app/using/inbox.html',
|
|
key: '--settings-recent-emails-show-help',
|
|
}}
|
|
>
|
|
{sortedRecentEmails.length > 0 ? (
|
|
sortedRecentEmails.map((recentEmail: RecentEmail, i) => {
|
|
return (
|
|
<SettingsTableRow
|
|
key={recentEmail.id}
|
|
title={recentEmail.from}
|
|
onClick={() => {
|
|
setViewingEmailHtml(recentEmail)
|
|
}}
|
|
isLast={i === sortedRecentEmails.length - 1}
|
|
sublineElement={
|
|
<VStack>
|
|
<StyledText
|
|
css={{
|
|
my: '5px',
|
|
fontSize: '14px',
|
|
}}
|
|
>
|
|
{recentEmail.subject}
|
|
</StyledText>
|
|
<StyledText
|
|
css={{
|
|
my: '0px',
|
|
fontSize: '11px',
|
|
a: {
|
|
color: '$omnivoreCtaYellow',
|
|
},
|
|
}}
|
|
>
|
|
<TypeChip type={recentEmail.type} />
|
|
</StyledText>
|
|
</VStack>
|
|
}
|
|
dropdownItems={
|
|
<>
|
|
<MoreOptionItem
|
|
text="View Text"
|
|
action={() => {
|
|
console.log('viewing text: ', recentEmail)
|
|
setViewingEmailText(recentEmail)
|
|
}}
|
|
/>
|
|
{recentEmail.type != 'article' && (
|
|
<MoreOptionItem
|
|
text="Mark as article"
|
|
action={async () => {
|
|
console.log('marking as email', recentEmail)
|
|
showSuccessToast('Marking email as article')
|
|
try {
|
|
await markEmailAsItemMutation(recentEmail.id)
|
|
revalidate()
|
|
} catch (err) {
|
|
console.log('error marking as article: ', err)
|
|
showErrorToast('Error marking item as article')
|
|
return
|
|
}
|
|
showSuccessToast('Email added to library')
|
|
}}
|
|
/>
|
|
)}
|
|
</>
|
|
}
|
|
/>
|
|
)
|
|
})
|
|
) : (
|
|
<EmptySettingsRow
|
|
text={isValidating ? '-' : 'No recent emails Found'}
|
|
/>
|
|
)}
|
|
|
|
{viewingEmailText && (
|
|
<ViewRecentEmailModal
|
|
display="text"
|
|
recentEmail={viewingEmailText}
|
|
onOpenChange={() => setViewingEmailText(undefined)}
|
|
/>
|
|
)}
|
|
{viewingEmailHtml && (
|
|
<ViewRecentEmailModal
|
|
display="html"
|
|
recentEmail={viewingEmailHtml}
|
|
onOpenChange={() => setViewingEmailHtml(undefined)}
|
|
/>
|
|
)}
|
|
</SettingsTable>
|
|
)
|
|
}
|