Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(native-app): Subpoena functionality in inbox in app #16213

Merged
merged 26 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1aadc18
feat: add urgent tag to inbox
thoreyjona Sep 16, 2024
ea1e703
feat: add urgent tag to urgent documents in list
thoreyjona Sep 17, 2024
b60c477
fix: undo small variant for alert
thoreyjona Sep 17, 2024
ef3f056
feat: use label component instead of alert
thoreyjona Sep 23, 2024
d28136b
feat: add download icon
thoreyjona Sep 24, 2024
4c08b57
feat: add actions mapper
thoreyjona Sep 24, 2024
3963c1f
feat: add locale to getDocument endpoint
thoreyjona Sep 25, 2024
d5ed9a6
feat: include new alert and confirmation props from the server
thoreyjona Sep 30, 2024
ae79c84
feat: add black text option to label and update icon
thoreyjona Sep 30, 2024
96ef5cc
chore: update danger icon for card as well
thoreyjona Sep 30, 2024
b2c4c52
feat: styling of there is only one action button
thoreyjona Sep 30, 2024
d300e42
fix: smaller actions buttons
thoreyjona Sep 30, 2024
012be49
fix: make sure to not show confirmed alert until document has loaded
thoreyjona Sep 30, 2024
47f2fac
feat: navigate back to inbox if user does not accept
thoreyjona Sep 30, 2024
c645c8f
chore: rename files from camelCase
thoreyjona Sep 30, 2024
fa36533
blackTextColor should be optional
thoreyjona Sep 30, 2024
730ef3a
fix: more type safety in get-buttons-for-actions
thoreyjona Sep 30, 2024
bd9d843
fix: maxWidth
thoreyjona Oct 1, 2024
0e6b1e9
feat: use isUrgent to decide if we should includeDocument or not
thoreyjona Oct 1, 2024
a4d9cbe
fix: rewrite some things in document detail to improve code readability
thoreyjona Oct 9, 2024
cbfdfeb
fix: address minor PR comments
thoreyjona Oct 9, 2024
5eb2885
fix: use urgent variant for label instead of blackTextColor prop
thoreyjona Oct 9, 2024
1326370
fix: don't mark document as read if user does not confirm reception o…
thoreyjona Oct 10, 2024
d5a3193
Merge branch 'main' into feat/app-receipt-of-urgent-documents
kodiakhq[bot] Oct 10, 2024
ead83e6
fix: top scrolling bug
thoreyjona Oct 11, 2024
adc7d79
Merge branch 'main' into feat/app-receipt-of-urgent-documents
kodiakhq[bot] Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added apps/native/app/src/assets/icons/download.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/native/app/src/assets/icons/download@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/native/app/src/assets/icons/download@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed apps/native/app/src/assets/icons/external-open.png
Binary file not shown.
Binary file removed apps/native/app/src/assets/icons/external-open@2x.png
Binary file not shown.
Binary file removed apps/native/app/src/assets/icons/external-open@3x.png
Binary file not shown.
16 changes: 16 additions & 0 deletions apps/native/app/src/graphql/fragments/document.fragment.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ fragment ListDocument on DocumentV2 {
opened
categoryId
bookmarked
isUrgent
actions {
type
title
icon
data
}
alert {
title
data
}
confirmation {
title
data
icon
}
thoreyjona marked this conversation as resolved.
Show resolved Hide resolved
sender {
id
name
Expand Down
4 changes: 2 additions & 2 deletions apps/native/app/src/graphql/queries/inbox.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ query GetDocumentsCategoriesAndSenders {
}
}

query GetDocument($input: DocumentInput!) {
documentV2(input: $input) {
query GetDocument($input: DocumentInput!, $locale: String) {
documentV2(input: $input, locale: $locale) {
...ListDocument
content {
type
Expand Down
3 changes: 2 additions & 1 deletion apps/native/app/src/messages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,14 @@ export const en: TranslatedMessages = {
'inbox.emptyListTitle': 'There are currently no documents',
'inbox.emptyListDescription':
'When you receive electronic documents from the government, they will appear here.',

'inbox.markAllAsReadPromptTitle': 'Do you want to mark all as read?',
'inbox.markAllAsReadPromptDescription': 'This action cannot be undone',
'inbox.markAllAsReadPromptCancel': 'Cancel',
'inbox.markAllAsReadPromptConfirm': 'Mark all as read',
'inbox.cardNoInboxDocuments':
'When you receive mail in your mailbox, it will appear here.',
'inbox.urgent': 'Urgent',
'inbox.openDocument': 'Open document',

// inbox filters
'inboxFilters.screenTitle': 'Filter documents',
Expand Down
2 changes: 2 additions & 0 deletions apps/native/app/src/messages/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ export const is = {
'inbox.markAllAsReadPromptConfirm': 'Merkja lesið',
'inbox.cardNoInboxDocuments':
'Þegar þú færð sendan póst í pósthólfið þá birtist hann hér.',
'inbox.urgent': 'Áríðandi',
'inbox.openDocument': 'Opna erindi',

// inbox filters
'inboxFilters.screenTitle': 'Sía skjöl',
Expand Down
149 changes: 122 additions & 27 deletions apps/native/app/src/screens/document-detail/document-detail.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { useApolloClient, useFragment_experimental } from '@apollo/client'
import { blue400, dynamicColor, Header, Loader } from '@ui'
import { Alert, blue400, dynamicColor, Header, Loader } from '@ui'
import { Problem } from '@ui/lib/problem/problem'
import React, { useEffect, useRef, useState } from 'react'
import { FormattedDate, useIntl } from 'react-intl'
import { Animated, Platform, StyleSheet, View } from 'react-native'
import {
Alert as RNAlert,
Animated,
Platform,
StyleSheet,
View,
} from 'react-native'
import {
Navigation,
NavigationFunctionComponent,
OptionsTopBarButton,
} from 'react-native-navigation'
Expand All @@ -13,11 +20,11 @@ import {
useNavigationComponentDidAppear,
} from 'react-native-navigation-hooks/dist'
import Pdf, { Source } from 'react-native-pdf'
import Share from 'react-native-share'
import WebView from 'react-native-webview'
import styled, { useTheme } from 'styled-components/native'
import {
DocumentV2,
DocumentV2Action,
ListDocumentFragmentDoc,
useGetDocumentQuery,
} from '../../graphql/types/schema'
Expand All @@ -26,11 +33,15 @@ import { useConnectivityIndicator } from '../../hooks/use-connectivity-indicator
import { toggleAction } from '../../lib/post-mail-action'
import { authStore } from '../../stores/auth-store'
import { useOrganizationsStore } from '../../stores/organizations-store'
import { usePreferencesStore } from '../../stores/preferences-store'
import { ButtonRegistry } from '../../utils/component-registry'
import { getButtonsForActions } from './utils/get-buttons-for-actions'
import { useBrowser } from '../../lib/use-browser'
import { shareFile } from './utils/share-file'

const Host = styled.SafeAreaView`
margin-left: 24px;
margin-right: 24px;
margin-left: ${({ theme }) => theme.spacing[2]}px;
margin-right: ${({ theme }) => theme.spacing[2]}px;
`

const Border = styled.View`
Expand All @@ -41,10 +52,23 @@ const Border = styled.View`
}))};
`

const ActionsWrapper = styled.View`
margin-bottom: ${({ theme }) => theme.spacing[2]}px;
margin-horizontal: ${({ theme }) => theme.spacing[2]}px;
gap: ${({ theme }) => theme.spacing[2]}px;
`
thoreyjona marked this conversation as resolved.
Show resolved Hide resolved

const PdfWrapper = styled.View`
flex: 1;
background-color: ${dynamicColor('background')};
`

const DocumentWrapper = styled.View<{ hasMarginTop?: boolean }>`
flex: 1;
margin-horizontal: ${({ theme }) => theme.spacing[2]}px;
margin-top: ${({ theme, hasMarginTop }) =>
hasMarginTop ? theme.spacing[2] : 0}px;
`
const regexForBr = /<br\s*\/>/gi

// Styles for html documents
Expand Down Expand Up @@ -200,15 +224,52 @@ const PdfViewer = React.memo(

export const DocumentDetailScreen: NavigationFunctionComponent<{
docId: string
}> = ({ componentId, docId }) => {
isUrgent?: boolean
}> = ({ componentId, docId, isUrgent }) => {
useNavigationOptions(componentId)

const client = useApolloClient()
const intl = useIntl()
const htmlStyles = useHtmlStyles()
const { locale } = usePreferencesStore()
const { openBrowser } = useBrowser()
const { getOrganizationLogoUrl } = useOrganizationsStore()
const [accessToken, setAccessToken] = useState<string>()
const [error, setError] = useState(false)
const [showConfirmedAlert, setShowConfirmedAlert] = useState(false)
const [visible, setVisible] = useState(false)
const [loaded, setLoaded] = useState(false)
const [pdfUrl, setPdfUrl] = useState('')
const [refetching, setRefetching] = useState(false)

const refetchDocumentContent = async () => {
setRefetching(true)
try {
const result = await docRes.refetch({
input: { id: docId, includeDocument: true },
})
if (result.data?.documentV2?.alert) {
setShowConfirmedAlert(true)
}
} finally {
markDocumentAsRead()
setRefetching(false)
}
}

const showConfirmationAlert = (confirmation: DocumentV2Action) => {
RNAlert.alert(confirmation.title ?? '', confirmation.data ?? '', [
{
text: intl.formatMessage({ id: 'inbox.markAllAsReadPromptCancel' }),
style: 'cancel',
onPress: () => Navigation.pop(componentId),
},
{
text: intl.formatMessage({ id: 'inbox.openDocument' }),
onPress: refetchDocumentContent,
},
])
}

// Check if we have the document in the cache
const doc = useFragment_experimental<DocumentV2>({
Expand All @@ -220,24 +281,42 @@ export const DocumentDetailScreen: NavigationFunctionComponent<{
returnPartialData: true,
})

// We want to make sure we don't include the document content if isUrgent is undefined/null since then we don't have
// the info from the server and don't want to make any assumptions about it just yet
const shouldIncludeDocument = isUrgent === false
thoreyjona marked this conversation as resolved.
Show resolved Hide resolved

// Fetch the document to get the content information
const docRes = useGetDocumentQuery({
variables: {
input: {
id: docId,
// If the document is urgent we need to check if the user needs to confirm reception of it before fetching the document data
includeDocument: shouldIncludeDocument,
},
locale: locale === 'is-IS' ? 'is' : 'en',
thoreyjona marked this conversation as resolved.
Show resolved Hide resolved
},
fetchPolicy: 'no-cache',
onCompleted: async (data) => {
const confirmation = data.documentV2?.confirmation
if (confirmation && !refetching) {
showConfirmationAlert(confirmation)
} else if (!confirmation && !refetching) {
// If the user has already confirmed accepting the document we fetch the content
refetchDocumentContent()
}
},
thoreyjona marked this conversation as resolved.
Show resolved Hide resolved
})

const Document = {
...(doc?.data || {}),
...(docRes.data?.documentV2 || {}),
}

const [visible, setVisible] = useState(false)
const [loaded, setLoaded] = useState(false)
const [pdfUrl, setPdfUrl] = useState('')
const hasActions = !!Document.actions?.length
const hasConfirmation = !!Document.confirmation
const hasAlert =
!!Document.alert && (Document.alert?.title || Document.alert?.data)
const showAlert = showConfirmedAlert || (hasAlert && !hasConfirmation)

const loading = docRes.loading || !accessToken
const fileTypeLoaded = !!Document?.content?.type
Expand All @@ -248,6 +327,8 @@ export const DocumentDetailScreen: NavigationFunctionComponent<{
Document?.content?.type.toLocaleLowerCase() === 'html' &&
Document.content?.value !== ''

const onShare = () => shareFile({ document: Document as DocumentV2, pdfUrl })

useConnectivityIndicator({
componentId,
rightButtons: getRightButtonsForDocumentDetail({
Expand All @@ -268,28 +349,18 @@ export const DocumentDetailScreen: NavigationFunctionComponent<{
)
}
if (buttonId === ButtonRegistry.ShareButton && loaded) {
if (Platform.OS === 'android') {
authStore.setState({ noLockScreenUntilNextAppStateActive: true })
}
Share.open({
title: Document.subject!,
subject: Document.subject!,
message: `${Document.sender!.name!} \n ${Document.subject!}`,
type: hasPdf ? 'application/pdf' : undefined,
url: hasPdf ? `file://${pdfUrl}` : Document.downloadUrl!,
})
onShare()
}
}, componentId)

useNavigationComponentDidAppear(() => {
setVisible(true)
})

useEffect(() => {
const markDocumentAsRead = () => {
if (Document.opened) {
return
}

// Let's mark the document as read in the cache and decrease unreadCount if it is not 0
client.cache.modify({
id: client.cache.identify({
Expand All @@ -312,6 +383,13 @@ export const DocumentDetailScreen: NavigationFunctionComponent<{
},
},
})
}

useEffect(() => {
if (Document.opened || !shouldIncludeDocument) {
return
}
markDocumentAsRead()
}, [Document.id])

useEffect(() => {
Expand Down Expand Up @@ -355,14 +433,31 @@ export const DocumentDetailScreen: NavigationFunctionComponent<{
isLoading={loading && !Document.subject}
hasBorder={false}
logo={getOrganizationLogoUrl(Document.sender?.name ?? '', 75)}
label={isUrgent ? intl.formatMessage({ id: 'inbox.urgent' }) : ''}
/>
</Host>
{showAlert && (
<ActionsWrapper>
thoreyjona marked this conversation as resolved.
Show resolved Hide resolved
{showConfirmedAlert && (
<Alert
type="success"
hasBorder
message={
Document.alert?.title ?? Document.alert?.data ?? undefined
}
/>
)}
{hasActions &&
getButtonsForActions(
openBrowser,
onShare,
componentId,
Document.actions,
)}
</ActionsWrapper>
)}
<Border />
<View
style={{
flex: 1,
}}
>
<DocumentWrapper>
<Animated.View
style={{
flex: 1,
Expand Down Expand Up @@ -439,7 +534,7 @@ export const DocumentDetailScreen: NavigationFunctionComponent<{
)}
</View>
)}
</View>
</DocumentWrapper>
</>
)
}
Expand Down
Loading
Loading