diff --git a/apps/infoalloggi/package-lock.json b/apps/infoalloggi/package-lock.json index ea32bc8..d4ca577 100644 --- a/apps/infoalloggi/package-lock.json +++ b/apps/infoalloggi/package-lock.json @@ -69,6 +69,7 @@ "react-hot-toast": "^2.5.2", "react-is": "^19.1.1", "react-leaflet": "^5.0.0", + "react-pdf": "^10.1.0", "react-phone-number-input": "^3.4.12", "react-reverse-portal": "^2.3.0", "react-select": "^5.10.2", @@ -2499,6 +2500,191 @@ "dev": true, "license": "MIT" }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.79.tgz", + "integrity": "sha512-0SkvRRjyxY35eniEsQsjPYUMWunKlAWvionJOzJJADZF5ZDf/sL+ncJbMTV5LUiHg1iHOvVjWcuDOx/GNXr/lA==", + "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.79", + "@napi-rs/canvas-darwin-arm64": "0.1.79", + "@napi-rs/canvas-darwin-x64": "0.1.79", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.79", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.79", + "@napi-rs/canvas-linux-arm64-musl": "0.1.79", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.79", + "@napi-rs/canvas-linux-x64-gnu": "0.1.79", + "@napi-rs/canvas-linux-x64-musl": "0.1.79", + "@napi-rs/canvas-win32-x64-msvc": "0.1.79" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.79.tgz", + "integrity": "sha512-ih6ZIztNDEXl7axvC4swOwLFrM9lOyJa9VAMq7xIBtEZhR/8IVDa0ZTup2fZEiTCmnjmXolzv7uDviHkOTEMKQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.79.tgz", + "integrity": "sha512-REMz1Fac2VlOYJDg+JjmQWSJc459cCgVom6GvKwWkDqzSjvG9BSo72MDmQY3uhb7r49Xuz5gTFcLYTfNcm4MoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.79.tgz", + "integrity": "sha512-uQxLg6Bll7zv/ljp/YIeiUFWfV9C/ESv+2ioUh60hIAypuhtg6hhtWE/KnoW7G48wQls5VUStvEnJbnJ7bPKlA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.79.tgz", + "integrity": "sha512-X37B//TVIipL/3RyvyfNlbQK2uyIaK3PJ2bH7ZeU+jpkaYprBsV15GCN/LHTYAi6R0F/c53zK3aSFNKkGHM/Og==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.79.tgz", + "integrity": "sha512-+T1fuau1heabE6zGXiqZBGPH5fTIQF+xEu/u4fuugxEiChRYlhnPjkw26MBi8ePg/jmzxLfJEij6LMJQ4AQa2A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.79.tgz", + "integrity": "sha512-KsrsR3+6uXv70W/1/kY0yRK4/bbdJgA1Vuxw4KyfSc6mjl1DMoYXDAjpBT/5w7AXy6cGG44jm3upvvt/y/dPfg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.79.tgz", + "integrity": "sha512-EXaENnSJD6au6z4aKN2PpU9eVNWUsRI2cApm8gCa0WSRMaiYXZsFkXQmhB+Vz2pXahOS8BN2Zd8S1IeML/LCtg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.79.tgz", + "integrity": "sha512-3xZhHlE9e3cd9D7Comy6/TTSs/8PUGXEXymIwYQrA1QxHojAlAOFlVai4rffzXd0bHylZu+/wD76LodvYqF1Yw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.79.tgz", + "integrity": "sha512-4yv550uCjIEoTFgrpxYZK67nFlDMCQa3LAheM2QrO+B8w1p5w04usIQSCHqHe6aPWlbLQCIqfVcew6/7Q4KuHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.79", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.79.tgz", + "integrity": "sha512-sD5qP2njBRnhNlTNFJDdpeCN6aR3qVamLySTwhX3ec8sdfeT/chf/x2dw2UXoIGMoVaVk/y2ifwxBj/h2a2jug==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.3.tgz", @@ -10765,7 +10951,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -13540,6 +13725,24 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-cancellable-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-2.0.0.tgz", + "integrity": "sha512-3SEQqTpV9oqVsIWqAcmDuaNeo7yBO3tqPtqGRcKkEo0lrzD3wqbKG9mkxO65KoOgXqj+zH2phJ2LiAsdzlogSw==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" + } + }, + "node_modules/make-event-props": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-2.0.0.tgz", + "integrity": "sha512-G/hncXrl4Qt7mauJEXSg3AcdYzmpkIITTNl5I+rH9sog5Yw0kK6vseJjCaPfOXqOqQuPUP89Rkhfz5kPS8ijtw==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, "node_modules/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -13611,6 +13814,23 @@ "node": ">= 0.10.0" } }, + "node_modules/merge-refs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz", + "integrity": "sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -14720,6 +14940,18 @@ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "license": "MIT" }, + "node_modules/pdfjs-dist": { + "version": "5.3.93", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.3.93.tgz", + "integrity": "sha512-w3fQKVL1oGn8FRyx5JUG5tnbblggDqyx2XzA5brsJ5hSuS+I0NdnJANhmeWKLjotdbPQucLBug5t0MeWr0AAdg==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.16.0 || >=22.3.0" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.71" + } + }, "node_modules/peberminta": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", @@ -16059,6 +16291,35 @@ "react-dom": "^19.0.0" } }, + "node_modules/react-pdf": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-10.1.0.tgz", + "integrity": "sha512-iUI1YqWgwwZcsXjrehTp3Yi8nT/bvTaWULaRMMyJWvoqqSlopk4LQQ9GDqUnDtX3gzT2glrqrLbjIPl56a+Q3w==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "dequal": "^2.0.3", + "make-cancellable-promise": "^2.0.0", + "make-event-props": "^2.0.0", + "merge-refs": "^2.0.0", + "pdfjs-dist": "5.3.93", + "tiny-invariant": "^1.0.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-phone-number-input": { "version": "3.4.12", "resolved": "https://registry.npmjs.org/react-phone-number-input/-/react-phone-number-input-3.4.12.tgz", @@ -18426,6 +18687,15 @@ "node": "20 || >=22" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", diff --git a/apps/infoalloggi/package.json b/apps/infoalloggi/package.json index 792826a..9427d73 100644 --- a/apps/infoalloggi/package.json +++ b/apps/infoalloggi/package.json @@ -18,7 +18,6 @@ "types": "node ./headers/type.js && tsc --noEmit" }, "version": "0.1.0", - "dependencies": { "@fattureincloud/fattureincloud-ts-sdk": "^2.1.1", "@hookform/resolvers": "^5.2.1", @@ -81,6 +80,7 @@ "react-hot-toast": "^2.5.2", "react-is": "^19.1.1", "react-leaflet": "^5.0.0", + "react-pdf": "^10.1.0", "react-phone-number-input": "^3.4.12", "react-reverse-portal": "^2.3.0", "react-select": "^5.10.2", diff --git a/apps/infoalloggi/src/components/allegato-iframe.tsx b/apps/infoalloggi/src/components/allegato-iframe.tsx index b3254b7..6a1f06d 100644 --- a/apps/infoalloggi/src/components/allegato-iframe.tsx +++ b/apps/infoalloggi/src/components/allegato-iframe.tsx @@ -1,9 +1,17 @@ +import dynamic from "next/dynamic"; import { useEffect, useRef, useState } from "react"; import { LoadingPage } from "~/components/loading"; import { cn } from "~/lib/utils"; import type { TempTokensToken } from "~/schemas/public/TempTokens"; import { api } from "~/utils/api"; +const PDFViewer = dynamic( + () => import("./pdf-viewer").then((mod) => mod.PDFViewer), + { + ssr: false, + loading: () => , + }, +); export const AllegatoIframe = ({ className, allegato, @@ -14,8 +22,27 @@ export const AllegatoIframe = ({ const if_ref = useRef(null); const { mutateAsync: getToken } = api.storage.getStorageToken.useMutation(); const [token, setToken] = useState(null); + const [isMobile, setIsMobile] = useState(false); + const [isIOS, setIsIOS] = useState(false); + const [isPDF, setIsPDF] = useState(false); + + useEffect(() => { + // Detect mobile and iOS + const userAgent = navigator.userAgent.toLowerCase(); + setIsMobile( + /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test( + userAgent, + ), + ); + setIsIOS(/iphone|ipad|ipod/i.test(userAgent)); + + // Try to detect if file is PDF from extension + setIsPDF(allegato.toLowerCase().endsWith(".pdf")); + }, [allegato]); + const handleIframeLoad = () => { if (if_ref.current?.contentWindow) { + // For images const img = if_ref.current.contentWindow.document.querySelector("img"); if (img) { img.style.width = "100%"; @@ -24,6 +51,7 @@ export const AllegatoIframe = ({ } } }; + useEffect(() => { async function set() { const token = await getToken(); @@ -35,6 +63,19 @@ export const AllegatoIframe = ({ if (!token) return ; const requestUrl = `/go-api/storage/get/${allegato}?token=${String(token)}`; + // For PDF on iOS, provide download link instead + if (isPDF && (isIOS || isMobile)) { + return ( +
+ +
+ ); + } return (
{ + const [numPages, setNumPages] = useState(); + const containerRef = useRef(null); + const [width, setWidth] = useState(0); + const file = useMemo(() => ({ url }), [url]); + + const onResize = useCallback((entries) => { + const [entry] = entries; + + if (entry) { + setWidth(entry.contentRect.width); + } + }, []); + + const observer = new ResizeObserver(onResize); + + useEffect(() => { + if (containerRef.current) { + observer.observe(containerRef.current); + setWidth(containerRef.current.offsetWidth); + } + }, []); + + function onDocumentLoadSuccess({ + numPages: nextNumPages, + }: PDFDocumentProxy): void { + setNumPages(nextNumPages); + } + + return ( +
+ } + onLoadSuccess={onDocumentLoadSuccess} + options={options} + > + {Array.from(new Array(numPages), (_el, index) => ( + + ))} + +
+ ); +}; diff --git a/apps/infoalloggi/src/components/servizio/annuncio_actions.tsx b/apps/infoalloggi/src/components/servizio/annuncio_actions.tsx index fab9c15..bffba7f 100644 --- a/apps/infoalloggi/src/components/servizio/annuncio_actions.tsx +++ b/apps/infoalloggi/src/components/servizio/annuncio_actions.tsx @@ -731,9 +731,7 @@ const AdminLavoraConferma = () => {
- -