Browse Source

fix docs file preview (#25)

Reviewed-on: #25
Co-authored-by: YaroslavBerkuta <yaroslavberkuta@gmail.com>
Co-committed-by: YaroslavBerkuta <yaroslavberkuta@gmail.com>
change/chat-conversation
YaroslavBerkuta 9 months ago committed by Vitalik Yatsenko
parent
commit
93c0661268
  1. 9
      src/modules/tasks/atoms/document-preview.atom.tsx
  2. 12
      src/modules/tasks/transforms/task-attachments.transforms.ts
  3. 12
      src/services/system/fs.service.ts
  4. 36
      src/shared/components/modals/preview-file-modal.smart-component.tsx
  5. 38
      src/shared/components/plugins/webview.component.tsx
  6. 2
      src/shared/exceptions/unknown.exception.ts
  7. 10
      src/shared/helpers/fs.helpers.ts
  8. 17
      src/shared/helpers/htm-content.helper.ts
  9. 1
      src/shared/helpers/index.ts
  10. 3
      src/shared/hooks/index.ts
  11. 27
      src/shared/hooks/use-file-content.hook.ts

9
src/modules/tasks/atoms/document-preview.atom.tsx

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
/* eslint-disable react-native/no-inline-styles */
import {
$size,
appEvents,
@ -9,6 +10,7 @@ import { @@ -9,6 +10,7 @@ import {
} from '@/shared'
import {
getIconNameByExtension,
getOriginFileName,
getUrlExtension,
isImage,
isVideo,
@ -28,11 +30,6 @@ export const DocumentPreview: FC<IProps> = ({ url, allowDelete, onDelete }) => { @@ -28,11 +30,6 @@ export const DocumentPreview: FC<IProps> = ({ url, allowDelete, onDelete }) => {
const { styles, theme } = useTheme(createStyles)
const [paused, setPaused] = useState(false)
const prepareFileName = () => {
const splitUrlArr = url.split('/')
return splitUrlArr[splitUrlArr.length - 1]
}
const iconName = getIconNameByExtension(url)
const renderPreview = () => {
@ -85,7 +82,7 @@ export const DocumentPreview: FC<IProps> = ({ url, allowDelete, onDelete }) => { @@ -85,7 +82,7 @@ export const DocumentPreview: FC<IProps> = ({ url, allowDelete, onDelete }) => {
/>
<Txt style={styles.label} weight="500" numberOfLines={1}>
{prepareFileName()}
{getOriginFileName(url)}
</Txt>
</View>
)

12
src/modules/tasks/transforms/task-attachments.transforms.ts

@ -2,14 +2,14 @@ import { IFile, ITaskDocument } from '@/shared' @@ -2,14 +2,14 @@ import { IFile, ITaskDocument } from '@/shared'
import { ShortTaskDocument } from '../interfaces'
export const transformDocToShortDoc = ({
id,
url,
id,
url,
}: ITaskDocument): ShortTaskDocument => ({
id,
url,
id,
url,
})
export const transformFileToShortDoc = ({
id,
uri: url,
id,
uri: url,
}: IFile): ShortTaskDocument => ({ id, url })

12
src/services/system/fs.service.ts

@ -60,8 +60,8 @@ const writeFile = (data: IWriteFileData) => { @@ -60,8 +60,8 @@ const writeFile = (data: IWriteFileData) => {
const path = directory + `/${data.fileName}`
RNFS.writeFile(path, data.content, 'utf8')
.then(success => resolve(path))
.catch(err => reject(false))
.then(() => resolve(path))
.catch(() => reject(false))
})
}
@ -147,7 +147,7 @@ const _downloadFile = ( @@ -147,7 +147,7 @@ const _downloadFile = (
fileUrl: string,
ext: string = 'jpg',
): Promise<string> => {
return new Promise((resolve, reject) => {
return new Promise((resolve, _) => {
let FILE_URL = fileUrl
RNFetchBlob.config({
@ -262,11 +262,7 @@ export const shareFile = async ( @@ -262,11 +262,7 @@ export const shareFile = async (
}
}
export const shareFileOutside = async (
fileUrl: string,
fileName: string,
fileType?: string,
) => {
export const shareFileOutside = async (fileUrl: string, fileName: string) => {
await mediaPermissionsService.requestWriteExternalStorageAndroidPermissions()
appEvents.emit('openInfoModal', {

36
src/shared/components/modals/preview-file-modal.smart-component.tsx

@ -24,23 +24,27 @@ export const PreviewFileModal = () => { @@ -24,23 +24,27 @@ export const PreviewFileModal = () => {
}
const renderItem = useMemo(() => {
if (params?.mimeType === FileType.PDF) {
return (
<PDFView
fadeInDuration={250.0}
style={{ flex: 1 }}
resource={params?.fileUrl}
resourceType={'url'}
/>
)
} else {
return (
<WebviewPlugin
url={`https://docs.google.com/gview?embedded=true&url=${params?.fileUrl}`}
/>
)
switch (params?.mimeType) {
case FileType.PDF:
return (
<PDFView
fadeInDuration={250.0}
style={{ flex: 1 }}
resource={params?.fileUrl}
resourceType={'url'}
/>
)
case FileType.TXT:
return <WebviewPlugin url={params?.fileUrl} renderHtml />
default:
console.log('url:', params?.fileUrl)
return (
<WebviewPlugin
url={`https://view.officeapps.live.com/op/embed.aspx?src=${params?.fileUrl}`}
/>
)
}
}, [params])
}, [params?.fileUrl])
return (
<Modal

38
src/shared/components/plugins/webview.component.tsx

@ -1,15 +1,19 @@ @@ -1,15 +1,19 @@
import { useTheme } from '@/shared/hooks'
import { htmlContent } from '@/shared/helpers'
import { useFileContent, useTheme } from '@/shared/hooks'
import React, { FC, useState } from 'react'
import { ActivityIndicator, View, StyleSheet } from 'react-native'
import { WebView } from 'react-native-webview'
interface IProps {
url: string
renderHtml?: boolean
}
export const WebviewPlugin: FC<IProps> = ({ url }) => {
export const WebviewPlugin: FC<IProps> = ({ url, renderHtml = false }) => {
const [loading, setLoading] = useState(true)
const { styles, theme } = useTheme(createStyles)
const { fileContent } = useFileContent(url)
return (
<View style={styles.container}>
{loading && (
@ -19,12 +23,30 @@ export const WebviewPlugin: FC<IProps> = ({ url }) => { @@ -19,12 +23,30 @@ export const WebviewPlugin: FC<IProps> = ({ url }) => {
color={theme.$loaderPrimary}
/>
)}
<WebView
source={{ uri: url }}
style={styles.webview}
mixedContentMode="always"
onLoadEnd={() => setLoading(false)}
/>
{renderHtml ? (
<WebView
source={{ html: htmlContent(fileContent) }}
style={styles.webview}
mixedContentMode="always"
onLoadEnd={() => setLoading(false)}
originWhitelist={['*']}
allowsInlineMediaPlayback
allowsFullscreenVideo
allowsFullscreenWebView
allowsBackForwardNavigationGestures
allowHtml={true}
/>
) : (
<WebView
source={{ uri: url }}
style={styles.webview}
mixedContentMode="always"
onLoadEnd={() => setLoading(false)}
javaScriptEnabled={true}
domStorageEnabled={true}
scalesPageToFit={true}
/>
)}
</View>
)
}

2
src/shared/exceptions/unknown.exception.ts

@ -1 +1 @@ @@ -1 +1 @@
export class UnknownException extends Error { }
export class UnknownException extends Error {}

10
src/shared/helpers/fs.helpers.ts

@ -271,7 +271,8 @@ export const getIconNameByExtension = (name: string) => { @@ -271,7 +271,8 @@ export const getIconNameByExtension = (name: string) => {
}
export const getUrlExtension = (link: string) => {
return link.split(/[#?]/)[0].split('.').pop().trim()
const split = link.split(/[#?]/)
return split[split.length - 1].split('.').pop().trim()
}
export const getFileNameFromUrl = (link: string) => {
@ -279,3 +280,10 @@ export const getFileNameFromUrl = (link: string) => { @@ -279,3 +280,10 @@ export const getFileNameFromUrl = (link: string) => {
const fileName = fileNameWithExtension.split('.').slice(0, -1).join('.')
return fileName
}
export const getOriginFileName = (url: string) => {
const splitUrlArr = url.split('.')
const fileName = splitUrlArr[splitUrlArr.length - 2]
const fileExpansion = getUrlExtension(url)
return `${fileName}.${fileExpansion}`
}

17
src/shared/helpers/htm-content.helper.ts

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
export const htmlContent = (content: string) => {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text File Viewer</title>
</head>
<body>
<p>
${content}
</p>
</body>
</html>
`
}

1
src/shared/helpers/index.ts

@ -21,3 +21,4 @@ export * from './url.helpers' @@ -21,3 +21,4 @@ export * from './url.helpers'
export * from './versions.helper'
export * from './configs.helpers'
export * from './copy-to-buffer.helper'
export * from './htm-content.helper'

3
src/shared/hooks/index.ts

@ -8,4 +8,5 @@ export * from './use-theme.hook' @@ -8,4 +8,5 @@ export * from './use-theme.hook'
export * from './use-navigation.hook'
export * from './use-keyboard.hook'
export * from './use-selected-executor.hook'
export * from './use-socket.hook'
export * from './use-socket.hook'
export * from './use-file-content.hook'

27
src/shared/hooks/use-file-content.hook.ts

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
import { useEffect, useState } from 'react'
export const useFileContent = (url: string) => {
const [fileContent, setFileContent] = useState('')
const fetchFileContent = async () => {
try {
const res = await fetch(url)
if (res.status !== 200) {
setFileContent('Помилка завантаження файлу!')
} else {
const content = await res.text()
setFileContent(content)
}
} catch (error) {
console.error('Error fetching file content:', error)
}
}
useEffect(() => {
fetchFileContent()
}, [url])
return {
fileContent,
}
}
Loading…
Cancel
Save