diff --git a/package.json b/package.json index 447c884..3e9efdc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "no-copy-frontend", - "version": "0.109.0", + "version": "0.110.0", "private": true, "scripts": { "dev": "next dev -p 2999", diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index c20a87a..fc99f20 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -1,9 +1,9 @@ -import Providers from '@/app/providers/getQueryServer' import type { Metadata } from "next"; import { NextIntlClientProvider, hasLocale } from 'next-intl'; import { notFound } from 'next/navigation'; import { routing } from '@/i18n/routing'; -import { ToastProvider } from '@/app/providers/ToastProvider'; +import ClientProviders from '@/app/providers/ClientProviders'; +import { Suspense } from 'react'; import "../styles/globals.css"; import "../styles/global-styles.scss"; @@ -30,14 +30,15 @@ export default async function RootLayout({ } return ( - + - - - {children} - - - + Loading...}> + + + {children} + + + ); diff --git a/src/app/[locale]/watch-doc/layout.tsx b/src/app/[locale]/watch-doc/layout.tsx index 63614ba..f78fe70 100644 --- a/src/app/[locale]/watch-doc/layout.tsx +++ b/src/app/[locale]/watch-doc/layout.tsx @@ -1,9 +1,14 @@ +'use client' + import { PdfProvider } from '@/app/contexts/PdfContext'; +import { WatchDocProviders } from '@/app/providers/ClientProviders'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - - {children} - + + + {children} + + ); } \ No newline at end of file diff --git a/src/app/[locale]/watch-doc/page.tsx b/src/app/[locale]/watch-doc/page.tsx index 5b10258..d1b4670 100644 --- a/src/app/[locale]/watch-doc/page.tsx +++ b/src/app/[locale]/watch-doc/page.tsx @@ -119,7 +119,7 @@ export default async function Page({ searchParams }: PageProps) {
{response?.permissions?.DOWNLOAD && ( - + )}
diff --git a/src/app/actions/trackingActions.ts b/src/app/actions/trackingActions.ts index e18bc2a..dd1125a 100644 --- a/src/app/actions/trackingActions.ts +++ b/src/app/actions/trackingActions.ts @@ -238,4 +238,27 @@ export async function fetchTrackingStats() { } catch (error) { return null; } +} + +export async function downloadTrackingFile(fileId: string, fileName?: string) { + try { + const response = await fetch(`${API_BASE_URL}/api/v1/files/public-download/${fileId}`, { + method: 'GET' + }); + + if (!response.ok) { + throw 'failed-to-download-file'; + } + + const arrayBuffer = await response.arrayBuffer() + const base64 = Buffer.from(arrayBuffer).toString('base64') + + return { + data: base64, + contentType: response.headers.get('content-type') || 'application/octet-stream', + fileName: fileName ? fileName : 'fileName' + } + } catch (error) { + return null; + } } \ No newline at end of file diff --git a/src/app/components/document-viewer/DownloadButton.tsx b/src/app/components/document-viewer/DownloadButton.tsx index 9129732..2b90df1 100644 --- a/src/app/components/document-viewer/DownloadButton.tsx +++ b/src/app/components/document-viewer/DownloadButton.tsx @@ -1,12 +1,49 @@ 'use client'; -import { usePdf } from '@/app/contexts/PdfContext'; +import { downloadTrackingFile } from '@/app/actions/trackingActions'; +import { useTranslations } from 'next-intl'; +import { toast } from 'sonner'; +interface DownloadButtonProps { + fileId: string; + fileName?: string; +} -export function DownloadButton() { - const { downloadPdf } = usePdf(); +export function DownloadButton({ fileId, fileName }: DownloadButtonProps) { + const t = useTranslations('Global'); + + const handleDownload = async () => { + try { + const result = await downloadTrackingFile(fileId, fileName); + + if (!result) { + throw 'failed-to-download-file' + } + + const byteCharacters = atob(result.data); + const byteNumbers = new Array(byteCharacters.length); + for (let i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i) + } + + const byteArray = new Uint8Array(byteNumbers); + const blob = new Blob([byteArray], { type: result.contentType }); + + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = result.fileName; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + toast.success(`${t('file-is-downloading')} - `); + } catch (error) { + toast.error(t('failed-to-download-file')); + } + }; return ( - ); diff --git a/src/app/providers/ClientProviders.tsx b/src/app/providers/ClientProviders.tsx new file mode 100644 index 0000000..b937ccb --- /dev/null +++ b/src/app/providers/ClientProviders.tsx @@ -0,0 +1,25 @@ +'use client'; + +import Providers from './getQueryServer'; +import { ToastProvider } from './ToastProvider'; + +export default function ClientProviders({ + children +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + + ); +} + +export function WatchDocProviders({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/src/app/providers/getQueryServer.tsx b/src/app/providers/getQueryServer.tsx index 4d43fc5..3f56041 100644 --- a/src/app/providers/getQueryServer.tsx +++ b/src/app/providers/getQueryServer.tsx @@ -1,34 +1,11 @@ 'use client' import { - isServer, - QueryClient, QueryClientProvider, } from '@tanstack/react-query' import { getQueryClient } from '@/app/providers/getQueryClient'; -/* export function makeQueryClient() { - return new QueryClient({ - defaultOptions: { - queries: { - staleTime: 60 * 1000, - }, - }, - }) -} - -let browserQueryClient: QueryClient | undefined = undefined - -function getQueryClient() { - if (isServer) { - return makeQueryClient() - } else { - if (!browserQueryClient) browserQueryClient = makeQueryClient() - return browserQueryClient - } -} */ - export default function Providers({ children }: { children: React.ReactNode }) { const queryClient = getQueryClient();