feat: add PDF generation and email sending for printable announcements
- Updated package.json to include html2canvas-pro and jsPDF for PDF generation. - Enhanced SchedaAnnuncioStampabile component to generate a PDF from HTML and send it via email. - Implemented new API endpoint for sending the generated PDF as an email attachment. - Refactored existing email sending logic across various controllers to use a unified template structure. - Improved error handling and logging for email sending processes.
This commit is contained in:
parent
b75e7f2412
commit
e5c0ca04ee
12 changed files with 713 additions and 251 deletions
337
apps/infoalloggi/package-lock.json
generated
337
apps/infoalloggi/package-lock.json
generated
|
|
@ -49,9 +49,11 @@
|
|||
"embla-carousel-react": "^8.6.0",
|
||||
"framer-motion": "^12.8.0",
|
||||
"frimousse": "^0.3.0",
|
||||
"html2canvas-pro": "^1.5.13",
|
||||
"ioredis": "^5.7.0",
|
||||
"jose": "^6.0.12",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jspdf": "^3.0.4",
|
||||
"kysely": "^0.28.2",
|
||||
"kysely-plugin-serialize": "^0.8.2",
|
||||
"leaflet": "^1.9.4",
|
||||
|
|
@ -76,7 +78,7 @@
|
|||
"react-is": "^19.1.1",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-number-format": "^5.4.4",
|
||||
"react-pdf": "^10.1.0",
|
||||
"react-pdf": "^10.2.0",
|
||||
"react-phone-number-input": "^3.4.12",
|
||||
"react-reverse-portal": "^2.3.0",
|
||||
"react-select": "^5.10.2",
|
||||
|
|
@ -997,9 +999,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.28.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz",
|
||||
"integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==",
|
||||
"version": "7.28.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
|
|
@ -2576,9 +2578,9 @@
|
|||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.82.tgz",
|
||||
"integrity": "sha512-FGjyUBoF0sl1EenSiE4UV2WYu76q6F9GSYedq5EiOCOyGYoQ/Owulcv6rd7v/tWOpljDDtefXXIaOCJrVKem4w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"workspaces": [
|
||||
|
|
@ -2588,22 +2590,22 @@
|
|||
"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"
|
||||
"@napi-rs/canvas-android-arm64": "0.1.82",
|
||||
"@napi-rs/canvas-darwin-arm64": "0.1.82",
|
||||
"@napi-rs/canvas-darwin-x64": "0.1.82",
|
||||
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.82",
|
||||
"@napi-rs/canvas-linux-arm64-gnu": "0.1.82",
|
||||
"@napi-rs/canvas-linux-arm64-musl": "0.1.82",
|
||||
"@napi-rs/canvas-linux-riscv64-gnu": "0.1.82",
|
||||
"@napi-rs/canvas-linux-x64-gnu": "0.1.82",
|
||||
"@napi-rs/canvas-linux-x64-musl": "0.1.82",
|
||||
"@napi-rs/canvas-win32-x64-msvc": "0.1.82"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.82.tgz",
|
||||
"integrity": "sha512-bvZhN0iI54ouaQOrgJV96H2q7J3ZoufnHf4E1fUaERwW29Rz4rgicohnAg4venwBJZYjGl5Yl3CGmlAl1LZowQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2617,9 +2619,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.82.tgz",
|
||||
"integrity": "sha512-InuBHKCyuFqhNwNr4gpqazo5Xp6ltKflqOLiROn4hqAS8u21xAHyYCJRgHwd+a5NKmutFTaRWeUIT/vxWbU/iw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2633,9 +2635,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.82.tgz",
|
||||
"integrity": "sha512-aQGV5Ynn96onSXcuvYb2y7TRXD/t4CL2EGmnGqvLyeJX1JLSNisKQlWN/1bPDDXymZYSdUqbXehj5qzBlOx+RQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2649,9 +2651,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.82.tgz",
|
||||
"integrity": "sha512-YIUpmHWeHGGRhWitT1KJkgj/JPXPfc9ox8oUoyaGPxolLGPp5AxJkq8wIg8CdFGtutget968dtwmx71m8o3h5g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -2665,9 +2667,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.82.tgz",
|
||||
"integrity": "sha512-AwLzwLBgmvk7kWeUgItOUor/QyG31xqtD26w1tLpf4yE0hiXTGp23yc669aawjB6FzgIkjh1NKaNS52B7/qEBQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2681,9 +2683,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.82.tgz",
|
||||
"integrity": "sha512-moZWuqepAwWBffdF4JDadt8TgBD02iMhG6I1FHZf8xO20AsIp9rB+p0B8Zma2h2vAF/YMjeFCDmW5un6+zZz9g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2697,9 +2699,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.82.tgz",
|
||||
"integrity": "sha512-w9++2df2kG9eC9LWYIHIlMLuhIrKGQYfUxs97CwgxYjITeFakIRazI9LYWgVzEc98QZ9x9GQvlicFsrROV59MQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
|
@ -2713,9 +2715,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.82.tgz",
|
||||
"integrity": "sha512-lZulOPwrRi6hEg/17CaqdwWEUfOlIJuhXxincx1aVzsVOCmyHf+xFq4i6liJl1P+x2v6Iz2Z/H5zHvXJCC7Bwg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2729,9 +2731,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.82.tgz",
|
||||
"integrity": "sha512-Be9Wf5RTv1w6GXlTph55K3PH3vsAh1Ax4T1FQY1UYM0QfD0yrwGdnJ8/fhqw7dEgMjd59zIbjJQC8C3msbGn5g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2745,9 +2747,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.1.82",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.82.tgz",
|
||||
"integrity": "sha512-LN/i8VrvxTDmEEK1c10z2cdOTkWT76LlTGtyZe5Kr1sqoSomKeExAjbilnu1+oee5lZUgS5yfZ2LNlVhCeARuw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -9207,6 +9209,12 @@
|
|||
"integrity": "sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/pako": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
|
||||
"integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
|
|
@ -9231,6 +9239,13 @@
|
|||
"integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/raf": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
||||
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz",
|
||||
|
|
@ -9271,6 +9286,13 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||
|
|
@ -9795,6 +9817,15 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
|
|
@ -10041,6 +10072,26 @@
|
|||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/canvg": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
|
||||
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/raf": "^3.4.0",
|
||||
"core-js": "^3.8.3",
|
||||
"raf": "^3.4.1",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"rgbcolor": "^1.0.1",
|
||||
"stackblur-canvas": "^2.0.0",
|
||||
"svg-pathdata": "^6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
|
|
@ -10351,6 +10402,18 @@
|
|||
"toggle-selection": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.47.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz",
|
||||
"integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
|
|
@ -10442,6 +10505,15 @@
|
|||
"hyphenate-style-name": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/css-line-break": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
||||
|
|
@ -10917,6 +10989,16 @@
|
|||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz",
|
||||
"integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optional": true,
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
|
|
@ -11469,6 +11551,17 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-png": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
|
||||
"integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/pako": "^2.0.3",
|
||||
"iobuffer": "^5.3.2",
|
||||
"pako": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-shallow-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz",
|
||||
|
|
@ -11536,6 +11629,12 @@
|
|||
"walk-up-path": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
|
|
@ -12118,6 +12217,33 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas-pro": {
|
||||
"version": "1.5.13",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas-pro/-/html2canvas-pro-1.5.13.tgz",
|
||||
"integrity": "sha512-//ksb3JLA+ewSxFODyb5YH6xqRLpe6Kt1i7Zyr5eqHmfcNt0bm8MpzSQjOK2qu6cCv13wqWtOZrCOpA+//EhaA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
|
|
@ -12251,6 +12377,12 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/iobuffer": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
|
||||
"integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ioredis": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz",
|
||||
|
|
@ -12879,6 +13011,23 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jspdf": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.4.tgz",
|
||||
"integrity": "sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"fast-png": "^6.2.0",
|
||||
"fflate": "^0.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"canvg": "^3.0.11",
|
||||
"core-js": "^3.6.0",
|
||||
"dompurify": "^3.2.4",
|
||||
"html2canvas": "^1.0.0-rc.5"
|
||||
}
|
||||
},
|
||||
"node_modules/kanel": {
|
||||
"version": "3.14.4",
|
||||
"resolved": "https://registry.npmjs.org/kanel/-/kanel-3.14.4.tgz",
|
||||
|
|
@ -14713,6 +14862,12 @@
|
|||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
|
|
@ -14812,15 +14967,15 @@
|
|||
"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==",
|
||||
"version": "5.4.296",
|
||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz",
|
||||
"integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20.16.0 || >=22.3.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@napi-rs/canvas": "^0.1.71"
|
||||
"@napi-rs/canvas": "^0.1.80"
|
||||
}
|
||||
},
|
||||
"node_modules/peberminta": {
|
||||
|
|
@ -14832,6 +14987,13 @@
|
|||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.16.3",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
|
|
@ -15701,6 +15863,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ramda": {
|
||||
"version": "0.30.1",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz",
|
||||
|
|
@ -16124,9 +16296,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-10.2.0.tgz",
|
||||
"integrity": "sha512-zk0DIL31oCh8cuQycM0SJKfwh4Onz0/Nwi6wTOjgtEjWGUY6eM+/vuzvOP3j70qtEULn7m1JtaeGzud1w5fY2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clsx": "^2.0.0",
|
||||
|
|
@ -16134,7 +16306,7 @@
|
|||
"make-cancellable-promise": "^2.0.0",
|
||||
"make-event-props": "^2.0.0",
|
||||
"merge-refs": "^2.0.0",
|
||||
"pdfjs-dist": "5.3.93",
|
||||
"pdfjs-dist": "5.4.296",
|
||||
"tiny-invariant": "^1.0.0",
|
||||
"warning": "^4.0.0"
|
||||
},
|
||||
|
|
@ -16552,6 +16724,13 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||
|
|
@ -16650,6 +16829,16 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rgbcolor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
||||
"license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8.15"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
|
||||
|
|
@ -17407,6 +17596,16 @@
|
|||
"stackframe": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/stackblur-canvas": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
||||
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/stackframe": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||
|
|
@ -17880,6 +18079,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-pathdata": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tagged-comment-parser": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/tagged-comment-parser/-/tagged-comment-parser-1.3.8.tgz",
|
||||
|
|
@ -18025,6 +18234,15 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/text-segmentation": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/thenify": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
|
|
@ -18427,6 +18645,15 @@
|
|||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -61,9 +61,11 @@
|
|||
"embla-carousel-react": "^8.6.0",
|
||||
"framer-motion": "^12.8.0",
|
||||
"frimousse": "^0.3.0",
|
||||
"html2canvas-pro": "^1.5.13",
|
||||
"ioredis": "^5.7.0",
|
||||
"jose": "^6.0.12",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jspdf": "^3.0.4",
|
||||
"kysely": "^0.28.2",
|
||||
"kysely-plugin-serialize": "^0.8.2",
|
||||
"leaflet": "^1.9.4",
|
||||
|
|
@ -88,7 +90,7 @@
|
|||
"react-is": "^19.1.1",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-number-format": "^5.4.4",
|
||||
"react-pdf": "^10.1.0",
|
||||
"react-pdf": "^10.2.0",
|
||||
"react-phone-number-input": "^3.4.12",
|
||||
"react-reverse-portal": "^2.3.0",
|
||||
"react-select": "^5.10.2",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import html2canvas from "html2canvas-pro";
|
||||
import jsPDF from "jspdf";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useReactToPrint } from "react-to-print";
|
||||
import { Button } from "~/components/ui/button";
|
||||
|
|
@ -10,6 +12,7 @@ import { handleConsegna } from "~/lib/annuncio_details";
|
|||
import { replaceWithBr } from "~/lib/newlineToBr";
|
||||
import { formatCurrency } from "~/lib/utils";
|
||||
import type { Annunci } from "~/schemas/public/Annunci";
|
||||
import { api } from "~/utils/api";
|
||||
import { IconMatrix } from "./IconComponents";
|
||||
import { GoogleMapsIcon, LogoSvg, WhatsAppIcon } from "./svgs";
|
||||
|
||||
|
|
@ -20,6 +23,119 @@ export function SchedaAnnuncioStampabile({ data }: { data: Annunci }) {
|
|||
//print: async (target) => {console.log("Printing...", target.contentDocument);},
|
||||
});
|
||||
|
||||
const { mutate } = api.comunicazioni.sendSchedaAnnuncioEmail.useMutation();
|
||||
const reactToPrintFn2 = useReactToPrint({
|
||||
contentRef,
|
||||
print: async (target) => {
|
||||
try {
|
||||
const htmlContent = target.contentDocument?.documentElement;
|
||||
if (!htmlContent) return;
|
||||
htmlContent.querySelectorAll(".print\\:border-none").forEach((el) => {
|
||||
el.classList.remove("border");
|
||||
});
|
||||
htmlContent.querySelectorAll(".print\\:shadow-none").forEach((el) => {
|
||||
el.classList.remove("shadow-sm");
|
||||
});
|
||||
|
||||
const canvas = await html2canvas(htmlContent, {
|
||||
//scale: 2,
|
||||
useCORS: true,
|
||||
logging: false,
|
||||
backgroundColor: "#ffffff",
|
||||
});
|
||||
|
||||
const imgData = canvas.toDataURL("image/png", 0.85);
|
||||
const pdf = new jsPDF("p", "mm", "a4");
|
||||
|
||||
// A4 dimensions in mm
|
||||
const pdfWidth = pdf.internal.pageSize.getWidth();
|
||||
const pdfHeight = pdf.internal.pageSize.getHeight();
|
||||
|
||||
// Define margins (in mm)
|
||||
const marginTop = 5;
|
||||
const marginRight = 5;
|
||||
const marginBottom = 5;
|
||||
const marginLeft = 5;
|
||||
|
||||
// Calculate available space
|
||||
const availableWidth = pdfWidth - marginLeft - marginRight;
|
||||
const availableHeight = pdfHeight - marginTop - marginBottom;
|
||||
|
||||
// Calculate image dimensions
|
||||
const imgProps = pdf.getImageProperties(imgData);
|
||||
const imgWidth = imgProps.width;
|
||||
const imgHeight = imgProps.height;
|
||||
|
||||
// Calculate how the image should fit with margins
|
||||
const ratio = availableWidth / imgWidth;
|
||||
const scaledHeight = imgHeight * ratio;
|
||||
|
||||
// Check if content needs multiple pages
|
||||
if (scaledHeight <= availableHeight) {
|
||||
// Single page - content fits
|
||||
pdf.addImage(
|
||||
imgData,
|
||||
"PNG",
|
||||
marginLeft,
|
||||
marginTop,
|
||||
availableWidth,
|
||||
scaledHeight,
|
||||
undefined,
|
||||
"FAST",
|
||||
);
|
||||
} else {
|
||||
// Multiple pages needed
|
||||
let heightLeft = scaledHeight;
|
||||
let position = marginTop;
|
||||
|
||||
// Add first page
|
||||
pdf.addImage(
|
||||
imgData,
|
||||
"PNG",
|
||||
marginLeft,
|
||||
position,
|
||||
availableWidth,
|
||||
scaledHeight,
|
||||
undefined,
|
||||
"FAST",
|
||||
);
|
||||
heightLeft -= availableHeight;
|
||||
|
||||
// Add remaining pages
|
||||
while (heightLeft > 0) {
|
||||
position = marginTop - (scaledHeight - heightLeft);
|
||||
pdf.addPage();
|
||||
pdf.addImage(
|
||||
imgData,
|
||||
"PNG",
|
||||
marginLeft,
|
||||
position,
|
||||
availableWidth,
|
||||
scaledHeight,
|
||||
undefined,
|
||||
"FAST",
|
||||
);
|
||||
heightLeft -= availableHeight;
|
||||
}
|
||||
}
|
||||
const pdfBase64 = pdf.output("dataurlstring");
|
||||
console.log(
|
||||
"PDF size:",
|
||||
((pdfBase64.length * 0.75) / 1024 / 1024).toFixed(2),
|
||||
"MB",
|
||||
);
|
||||
|
||||
mutate({
|
||||
pdf: pdfBase64,
|
||||
to: "m.pedone98@gmail.com",
|
||||
codice: data.codice,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Error during print:", e);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<div className="space-y-6">
|
||||
|
|
@ -29,6 +145,9 @@ export function SchedaAnnuncioStampabile({ data }: { data: Annunci }) {
|
|||
<Button className="print:hidden" onClick={() => reactToPrintFn()}>
|
||||
Stampa
|
||||
</Button>
|
||||
<Button className="print:hidden" onClick={() => reactToPrintFn2()}>
|
||||
Stampa
|
||||
</Button>
|
||||
</div>
|
||||
<div ref={contentRef}>
|
||||
<SchedaAnnuncio data={data} />
|
||||
|
|
@ -38,7 +157,7 @@ export function SchedaAnnuncioStampabile({ data }: { data: Annunci }) {
|
|||
);
|
||||
}
|
||||
|
||||
function SchedaAnnuncio({ data }: { data: Annunci }) {
|
||||
export function SchedaAnnuncio({ data }: { data: Annunci }) {
|
||||
const companyAddress =
|
||||
"Via Beata Giovanna, 1 a Bassano del Grappa (VI)\nTel. +39 0424529869\nEmail: arca@infoalloggi.it";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import { z } from "zod/v4";
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
import {
|
||||
adminProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
} from "~/server/api/trpc";
|
||||
import { GetEmails } from "~/server/services/email.service";
|
||||
import { NewMail } from "~/server/services/mailer";
|
||||
import { zUserId } from "~/server/utils/zod_types";
|
||||
|
||||
export const comunicazioniRouter = createTRPCRouter({
|
||||
|
|
@ -35,4 +40,45 @@ export const comunicazioniRouter = createTRPCRouter({
|
|||
// userId: input.userId,
|
||||
// });
|
||||
// }),
|
||||
sendSchedaAnnuncioEmail: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
pdf: z.string(),
|
||||
codice: z.string(),
|
||||
to: z.email(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const base64Content = input.pdf.includes("base64,")
|
||||
? input.pdf.split("base64,")[1]
|
||||
: input.pdf;
|
||||
await NewMail({
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
noreply: true,
|
||||
testo: `In allegato la scheda annuncio stampabile per l'annuncio con codice ${input.codice}.`,
|
||||
title: "Scheda Annuncio Stampabile",
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: `Scheda Annuncio ${input.codice} - Infoalloggi.it`,
|
||||
to: input.to,
|
||||
attachments: [
|
||||
{
|
||||
filename: `scheda-annuncio-${input.codice}.pdf`,
|
||||
content: base64Content,
|
||||
encoding: "base64",
|
||||
contentType: "application/pdf",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Errore nell'invio dell'email: ${(e as Error).message}`,
|
||||
);
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,16 +22,20 @@ export const contactRouter = createTRPCRouter({
|
|||
)
|
||||
.mutation(async ({ input }) => {
|
||||
await NewMail({
|
||||
mailType: "contattoAdminEmail",
|
||||
props: {
|
||||
cognome: input.cognome,
|
||||
email: input.email,
|
||||
messaggio: input.messaggio,
|
||||
nome: input.nome,
|
||||
telefono: input.telefono,
|
||||
template: {
|
||||
mailType: "contattoAdminEmail",
|
||||
props: {
|
||||
cognome: input.cognome,
|
||||
email: input.email,
|
||||
messaggio: input.messaggio,
|
||||
nome: input.nome,
|
||||
telefono: input.telefono,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: `Richiesta di contatto da ${input.nome}`,
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
subject: `Richiesta di contatto da ${input.nome}`,
|
||||
to: "web@infoalloggi.it",
|
||||
});
|
||||
return { success: true };
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -50,17 +50,21 @@ export const intrestsRouter = createTRPCRouter({
|
|||
});
|
||||
}
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${userId}`,
|
||||
label: "Visualizza utente",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${userId}`,
|
||||
label: "Visualizza utente",
|
||||
},
|
||||
testo: `L'utente ${user.username} (${user.email}) ha mostrato interesse per l'annuncio "${annuncio.titolo_it}" (Codice: ${annuncio.codice}).`,
|
||||
title: "Nuovo interesse per un annuncio",
|
||||
},
|
||||
testo: `L'utente ${user.username} (${user.email}) ha mostrato interesse per l'annuncio "${annuncio.titolo_it}" (Codice: ${annuncio.codice}).`,
|
||||
title: "Nuovo interesse per un annuncio",
|
||||
},
|
||||
subject: "Utente interessato ad un annuncio",
|
||||
to: "web@infoalloggi.it",
|
||||
mail: {
|
||||
subject: "Utente interessato ad un annuncio",
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
userId,
|
||||
});
|
||||
return { success: true };
|
||||
|
|
|
|||
|
|
@ -76,11 +76,12 @@ export const processEvents = async () => {
|
|||
const data = e.data as EventDataTypes;
|
||||
|
||||
switch (data.tipo) {
|
||||
case "email":
|
||||
case "email": {
|
||||
await NewMail({
|
||||
...data.data,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case "sms":
|
||||
await SendMessage(data.data);
|
||||
|
|
|
|||
|
|
@ -929,32 +929,40 @@ export const SbloccaContatti = async ({
|
|||
|
||||
const EmailProprietario: NewMailProps | null = data.annuncio.email
|
||||
? {
|
||||
mailType: "emailContattoInteressato",
|
||||
props: {
|
||||
indirizzo: data.annuncio.indirizzo,
|
||||
nome_cognome: data.annuncio.locatore || "",
|
||||
nome_cognome_utente: data.user.username,
|
||||
sesso: data.anagrafica.sesso,
|
||||
telefono: data.user.telefono,
|
||||
template: {
|
||||
mailType: "emailContattoInteressato",
|
||||
props: {
|
||||
indirizzo: data.annuncio.indirizzo,
|
||||
nome_cognome: data.annuncio.locatore || "",
|
||||
nome_cognome_utente: data.user.username,
|
||||
sesso: data.anagrafica.sesso,
|
||||
telefono: data.user.telefono,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: "Un interessato ha ricevuto i Suoi contatti",
|
||||
to: data.annuncio.email,
|
||||
},
|
||||
subject: "Un interessato ha ricevuto i Suoi contatti",
|
||||
to: data.annuncio.email,
|
||||
}
|
||||
: null;
|
||||
|
||||
const EmailInteressato: NewMailProps = {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/dashboard#${servizioId}-${annuncioId}`,
|
||||
label: "Vai al servizio",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/dashboard#${servizioId}-${annuncioId}`,
|
||||
label: "Vai al servizio",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `I contatti per l'annuncio ${data.annuncio.codice} sono stati sbloccati con successo.`,
|
||||
title: "Contatti sbloccati per il servizio di ricerca affitto",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `I contatti per l'annuncio ${data.annuncio.codice} sono stati sbloccati con successo.`,
|
||||
title: "Contatti sbloccati per il servizio di ricerca affitto",
|
||||
},
|
||||
subject: "Contatti sbloccati per il servizio di ricerca affitto",
|
||||
to: data.user.email,
|
||||
mail: {
|
||||
subject: "Contatti sbloccati per il servizio di ricerca affitto",
|
||||
to: data.user.email,
|
||||
},
|
||||
};
|
||||
const numeroProprietario = data.annuncio.numero
|
||||
? data.annuncio.numero.replace(/\s+/g, "").split(",")[0] || null
|
||||
|
|
@ -1053,30 +1061,38 @@ export const interruzioneServizio = async (servizioId: ServizioServizioId) => {
|
|||
// NOTIFICHE EMAIL INTERRUZIONE SERVIZIO
|
||||
const utente = await getUser({ db, userId: servizio.user_id });
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
noreply: true,
|
||||
testo: `Abbiamo ricevuto la tua richiesta di interruzione del servizio di ricerca affitto per la tipologia ${servizio.tipologia}. Il servizio è stato interrotto con successo.`,
|
||||
title: `Servizio Ricerca Affitto ${servizio.tipologia} interrotto`,
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
noreply: true,
|
||||
testo: `Abbiamo ricevuto la tua richiesta di interruzione del servizio di ricerca affitto per la tipologia ${servizio.tipologia}. Il servizio è stato interrotto con successo.`,
|
||||
title: `Servizio Ricerca Affitto ${servizio.tipologia} interrotto`,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: `Servizio Ricerca Affitto ${servizio.tipologia} interrotto`,
|
||||
to: utente.email,
|
||||
},
|
||||
subject: `Servizio Ricerca Affitto ${servizio.tipologia} interrotto`,
|
||||
to: utente.email,
|
||||
userId: utente.id,
|
||||
});
|
||||
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${servizio.user_id}#${servizioId}`,
|
||||
label: "Vai al servizio",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${servizio.user_id}#${servizioId}`,
|
||||
label: "Vai al servizio",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `L'utente ha richiesto l'interruzione del servizio di ricerca affitto per la tipologia ${servizio.tipologia}. Puoi procedere con le prossime azioni.`,
|
||||
title: `Utente ${utente.username} ha richieto l'interruzione del servizio di ricerca affitto`,
|
||||
},
|
||||
noreply: true,
|
||||
testo: `L'utente ha richiesto l'interruzione del servizio di ricerca affitto per la tipologia ${servizio.tipologia}. Puoi procedere con le prossime azioni.`,
|
||||
title: `Utente ${utente.username} ha richieto l'interruzione del servizio di ricerca affitto`,
|
||||
},
|
||||
subject: `Utente ${utente.username} ha richieto l'interruzione del servizio di ricerca affitto`,
|
||||
to: "web@infoalloggi.it",
|
||||
mail: {
|
||||
subject: `Utente ${utente.username} ha richieto l'interruzione del servizio di ricerca affitto`,
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
});
|
||||
|
||||
return true;
|
||||
|
|
@ -1174,21 +1190,25 @@ export const sendServizioEmail = async ({
|
|||
|
||||
const { email, nome } = user;
|
||||
await NewMail({
|
||||
mailType: "onboardingServizio",
|
||||
props: {
|
||||
annunci: annunci.map((annuncio) => ({
|
||||
codice: annuncio.codice,
|
||||
immagine: annuncio?.images
|
||||
? annuncio.images[0]?.img || "fallback"
|
||||
: "fallback",
|
||||
prezzo: annuncio.prezzo,
|
||||
titolo: annuncio.titolo_it,
|
||||
})),
|
||||
nome,
|
||||
token: servizioId,
|
||||
template: {
|
||||
mailType: "onboardingServizio",
|
||||
props: {
|
||||
annunci: annunci.map((annuncio) => ({
|
||||
codice: annuncio.codice,
|
||||
immagine: annuncio?.images
|
||||
? annuncio.images[0]?.img || "fallback"
|
||||
: "fallback",
|
||||
prezzo: annuncio.prezzo,
|
||||
titolo: annuncio.titolo_it,
|
||||
})),
|
||||
nome,
|
||||
token: servizioId,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: "Procedi ora su Infoalloggi.it",
|
||||
to: email,
|
||||
},
|
||||
subject: "Procedi ora su Infoalloggi.it",
|
||||
to: email,
|
||||
userId,
|
||||
});
|
||||
await db
|
||||
|
|
@ -1247,29 +1267,37 @@ export const userSendConfermaIntent = async ({
|
|||
.executeTakeFirstOrThrow();
|
||||
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${servizio.user_id}#${servizioId}-${annuncioId}`,
|
||||
label: "Visualizza Annuncio",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${servizio.user_id}#${servizioId}-${annuncioId}`,
|
||||
label: "Visualizza Annuncio",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `L'utente ${utente.username} ha confermato l'immobile con codice ${annuncio_codice.codice}.`,
|
||||
title: `Nuova conferma immobile ${annuncio_codice.codice}`,
|
||||
},
|
||||
noreply: true,
|
||||
testo: `L'utente ${utente.username} ha confermato l'immobile con codice ${annuncio_codice.codice}.`,
|
||||
title: `Nuova conferma immobile ${annuncio_codice.codice}`,
|
||||
},
|
||||
subject: `Nuova conferma immobile ${annuncio_codice.codice}`,
|
||||
to: "web@infoalloggi.it",
|
||||
mail: {
|
||||
subject: `Nuova conferma immobile ${annuncio_codice.codice}`,
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
});
|
||||
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
noreply: true,
|
||||
testo: `La tua conferma per l'immobile con codice ${annuncio_codice.codice} è stata ricevuta. Il nostro team la esaminerà a breve. Riceverai una notifica via email per procedere.`,
|
||||
title: `Conferma immobile ${annuncio_codice.codice} ricevuta`,
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
noreply: true,
|
||||
testo: `La tua conferma per l'immobile con codice ${annuncio_codice.codice} è stata ricevuta. Il nostro team la esaminerà a breve. Riceverai una notifica via email per procedere.`,
|
||||
title: `Conferma immobile ${annuncio_codice.codice} ricevuta`,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: `Conferma immobile ${annuncio_codice.codice} ricevuta`,
|
||||
to: utente.email,
|
||||
},
|
||||
subject: `Conferma immobile ${annuncio_codice.codice} ricevuta`,
|
||||
to: utente.email,
|
||||
userId: utente.id,
|
||||
});
|
||||
return true;
|
||||
|
|
@ -1305,18 +1333,22 @@ export const adminUpdateConfermaStatus = async ({
|
|||
//ADMIN CONFERMA LAVORATA EMAIL
|
||||
if (status) {
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/dashboard#${servizioId}-${annuncioId}`,
|
||||
label: "Vai al servizio",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/dashboard#${servizioId}-${annuncioId}`,
|
||||
label: "Vai al servizio",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `La conferma è stata lavorata con successo. Puoi procedere con le prossime azioni.`,
|
||||
title: "Conferma lavorata per il servizio di ricerca affitto",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `La conferma è stata lavorata con successo. Puoi procedere con le prossime azioni.`,
|
||||
title: "Conferma lavorata per il servizio di ricerca affitto",
|
||||
},
|
||||
subject: "Conferma lavorata per il servizio di ricerca affitto",
|
||||
to: utente.email,
|
||||
mail: {
|
||||
subject: "Conferma lavorata per il servizio di ricerca affitto",
|
||||
to: utente.email,
|
||||
},
|
||||
userId: utente.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -1353,18 +1385,22 @@ export const userAccettaConferma = async ({
|
|||
// USER ACCETTA CONFERMA EMAIL
|
||||
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${servizio.user_id}#${servizioId}-${annuncioId}`,
|
||||
label: "Vai al servizio",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/admin/user-view/ricerca/${servizio.user_id}#${servizioId}-${annuncioId}`,
|
||||
label: "Vai al servizio",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `L'utente ha accettato le condizioni di conferma per la locazione. Puoi procedere con le prossime azioni.`,
|
||||
title: `Utente ${utente.username} ha accettato le condizioni di conferma`,
|
||||
},
|
||||
noreply: true,
|
||||
testo: `L'utente ha accettato le condizioni di conferma per la locazione. Puoi procedere con le prossime azioni.`,
|
||||
title: `Utente ${utente.username} ha accettato le condizioni di conferma`,
|
||||
},
|
||||
subject: `Utente ${utente.username} ha accettato le condizioni di conferma`,
|
||||
to: "web@infoalloggi.it",
|
||||
mail: {
|
||||
subject: `Utente ${utente.username} ha accettato le condizioni di conferma`,
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
});
|
||||
|
||||
return true;
|
||||
|
|
@ -1552,16 +1588,20 @@ export const SendContactEmail = async ({
|
|||
}) => {
|
||||
try {
|
||||
await NewMail({
|
||||
mailType: "contattoAnnuncioEmail",
|
||||
props: {
|
||||
codice,
|
||||
email,
|
||||
messaggio,
|
||||
nome,
|
||||
telefono,
|
||||
template: {
|
||||
mailType: "contattoAnnuncioEmail",
|
||||
props: {
|
||||
codice,
|
||||
email,
|
||||
messaggio,
|
||||
nome,
|
||||
telefono,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: "Contatto per annuncio",
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
subject: "Contatto per annuncio",
|
||||
to: "web@infoalloggi.it",
|
||||
});
|
||||
return {
|
||||
email,
|
||||
|
|
|
|||
|
|
@ -155,13 +155,17 @@ export const SendMessage = async (data: MinimalSMSData) => {
|
|||
console.error("Error:", error);
|
||||
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
testo: `Errore durante l'invio dell'SMS: to:${data.recipient.join(", ")} Mgs:${data.message}; ${error instanceof Error ? error.message : String(error)}`,
|
||||
title: "Errore invio SMS",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
testo: `Errore durante l'invio dell'SMS: to:${data.recipient.join(", ")} Mgs:${data.message}; ${error instanceof Error ? error.message : String(error)}`,
|
||||
title: "Errore invio SMS",
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: "Errore invio SMS",
|
||||
to: "web@infoalloggi.it",
|
||||
},
|
||||
subject: "Errore invio SMS",
|
||||
to: "web@infoalloggi.it",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -135,19 +135,23 @@ export const whIntentSucceededHandler = async ({
|
|||
.execute();
|
||||
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
label: "Vai alla ricevuta",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
label: "Vai alla ricevuta",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `Il pagamento dell'acconto per il servizio ${ordine.packid} è stato confermato.`,
|
||||
title: "Pagamento Confermato ",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `Il pagamento dell'acconto per il servizio ${ordine.packid} è stato confermato.`,
|
||||
title: "Pagamento Confermato ",
|
||||
},
|
||||
subject: "Pagamento Confermato - Acconto Infoalloggi.it",
|
||||
to: utente.email,
|
||||
mail: {
|
||||
subject: "Pagamento Confermato - Acconto Infoalloggi.it",
|
||||
to: utente.email,
|
||||
},
|
||||
userId: utente.id,
|
||||
});
|
||||
break;
|
||||
|
|
@ -163,18 +167,22 @@ export const whIntentSucceededHandler = async ({
|
|||
})
|
||||
.execute();
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
label: "Vai alla ricevuta",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
label: "Vai alla ricevuta",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `Il pagamento del saldo per il servizio ${ordine.packid} è stato confermato.`,
|
||||
title: "Pagamento Confermato ",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `Il pagamento del saldo per il servizio ${ordine.packid} è stato confermato.`,
|
||||
title: "Pagamento Confermato ",
|
||||
},
|
||||
subject: "Pagamento Confermato - Saldo Infoalloggi.it",
|
||||
to: utente.email,
|
||||
mail: {
|
||||
subject: "Pagamento Confermato - Saldo Infoalloggi.it",
|
||||
to: utente.email,
|
||||
},
|
||||
userId: utente.id,
|
||||
});
|
||||
break;
|
||||
|
|
@ -187,30 +195,38 @@ export const whIntentSucceededHandler = async ({
|
|||
})
|
||||
.execute();
|
||||
await NewMail({
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
label: "Vai alla ricevuta",
|
||||
template: {
|
||||
mailType: "generic",
|
||||
props: {
|
||||
link: {
|
||||
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
label: "Vai alla ricevuta",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `Il pagamento per la consulenza è stato confermato.`,
|
||||
title: "Pagamento Confermato ",
|
||||
},
|
||||
noreply: true,
|
||||
testo: `Il pagamento per la consulenza è stato confermato.`,
|
||||
title: "Pagamento Confermato ",
|
||||
},
|
||||
subject: "Pagamento Confermato - Consulenza Infoalloggi.it",
|
||||
to: utente.email,
|
||||
mail: {
|
||||
subject: "Pagamento Confermato - Consulenza Infoalloggi.it",
|
||||
to: utente.email,
|
||||
},
|
||||
userId: utente.id,
|
||||
});
|
||||
break;
|
||||
case OrderTypeEnum.Altro:
|
||||
// TODO: Handle other types
|
||||
await NewMail({
|
||||
mailType: "pagamentoConferma",
|
||||
props: {
|
||||
receiptHref: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
template: {
|
||||
mailType: "pagamentoConferma",
|
||||
props: {
|
||||
receiptHref: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: "Pagamento Confermato",
|
||||
to: utente.email,
|
||||
},
|
||||
subject: "Pagamento Confermato",
|
||||
to: utente.email,
|
||||
userId: utente.id,
|
||||
});
|
||||
break;
|
||||
|
|
@ -246,9 +262,13 @@ export const whIntentFailedHandler = async ({
|
|||
});
|
||||
|
||||
await NewMail({
|
||||
mailType: "pagamentoErrore",
|
||||
subject: "Pagamento Fallito",
|
||||
to: utente.email,
|
||||
template: {
|
||||
mailType: "pagamentoErrore",
|
||||
},
|
||||
mail: {
|
||||
subject: "Pagamento Fallito",
|
||||
to: utente.email,
|
||||
},
|
||||
userId: utente.id,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,12 +115,16 @@ export const resetPasswordFromTokenHandler = async ({
|
|||
export const pwResetSendLinkHandler = async ({ email }: { email: string }) => {
|
||||
const { token, userId } = await pwResetTokenFromMailHandler({ email });
|
||||
await NewMail({
|
||||
mailType: "pwResetLink",
|
||||
props: {
|
||||
resetlink: `${env.BASE_URL}/auth/password-reset/${token}`,
|
||||
template: {
|
||||
mailType: "pwResetLink",
|
||||
props: {
|
||||
resetlink: `${env.BASE_URL}/auth/password-reset/${token}`,
|
||||
},
|
||||
},
|
||||
mail: {
|
||||
subject: `Richiesta di reset password Infoalloggi.it`,
|
||||
to: email,
|
||||
},
|
||||
subject: `Richiesta di reset password Infoalloggi.it`,
|
||||
to: email,
|
||||
userId,
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,12 +38,7 @@ import { GetFlagValueHandler } from "~/server/controllers/flags.controller";
|
|||
import { db } from "~/server/db";
|
||||
import { StoreEmail } from "~/server/services/email.service";
|
||||
|
||||
type MailerProps = {
|
||||
to: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
};
|
||||
const mailer = async ({ to, subject, html }: MailerProps) => {
|
||||
const mailer = async (options: Options) => {
|
||||
const smtpTransport = createTransport({
|
||||
auth: {
|
||||
pass: env.ARUBA_PASS,
|
||||
|
|
@ -63,9 +58,7 @@ const mailer = async ({ to, subject, html }: MailerProps) => {
|
|||
|
||||
const message: Options = {
|
||||
from: `"InfoAlloggi" <${env.ARUBA_USER}>`,
|
||||
html: html,
|
||||
subject: subject,
|
||||
to: to,
|
||||
...options,
|
||||
};
|
||||
smtpTransport.sendMail(message, (err, info) => {
|
||||
if (err) {
|
||||
|
|
@ -75,13 +68,11 @@ const mailer = async ({ to, subject, html }: MailerProps) => {
|
|||
});
|
||||
};
|
||||
|
||||
type base_NewMailProps = {
|
||||
export type NewMailProps = {
|
||||
template?: MailsTemplates;
|
||||
userId?: UsersId;
|
||||
to: string;
|
||||
subject: string;
|
||||
mail: Options;
|
||||
};
|
||||
|
||||
export type NewMailProps = base_NewMailProps & MailsTemplates;
|
||||
export type MailsTemplates =
|
||||
| ContattoAdmin_NewMail
|
||||
| ContattoAnnuncio_NewMail
|
||||
|
|
@ -185,24 +176,24 @@ export const genMail = async ({ ...mail }: MailsTemplates) => {
|
|||
return { html: await render(mailComponent), title };
|
||||
};
|
||||
|
||||
export const NewMail = async ({
|
||||
userId,
|
||||
to,
|
||||
subject,
|
||||
...mail
|
||||
}: NewMailProps) => {
|
||||
export const NewMail = async ({ template, userId, mail }: NewMailProps) => {
|
||||
const emailFlag = await GetFlagValueHandler({
|
||||
db: db,
|
||||
id: "EMAIL_OFF",
|
||||
});
|
||||
if (emailFlag === "false") {
|
||||
try {
|
||||
const { html } = await genMail({ ...mail });
|
||||
await mailer({
|
||||
html,
|
||||
subject: subject,
|
||||
to: to,
|
||||
});
|
||||
if (template) {
|
||||
const { html } = await genMail({ ...template });
|
||||
await mailer({
|
||||
html,
|
||||
...mail,
|
||||
});
|
||||
} else {
|
||||
await mailer({
|
||||
...mail,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
|
|
@ -211,12 +202,12 @@ export const NewMail = async ({
|
|||
}
|
||||
} else {
|
||||
console.warn(
|
||||
`Email sending is disabled to:${to} subj:${subject} msgType: ${mail.mailType}`,
|
||||
`Email sending is disabled to:${mail.to} subj:${mail.subject} msgType: ${template?.mailType}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (userId) {
|
||||
if (userId && template) {
|
||||
// Store the email in the database if userId is provided
|
||||
await StoreEmail({ data: mail, userId });
|
||||
await StoreEmail({ data: template, userId });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue