From 7b7a02554ea2f7530cd1836ff69d7b375fc78384 Mon Sep 17 00:00:00 2001 From: Alexander Petkov Date: Wed, 24 Apr 2024 16:27:42 +0300 Subject: [PATCH 1/2] chore(campaigns): Remove description char limit when creating campaign Needed by the campaign team, until we figure out how to translate the campaign text --- src/components/admin/campaigns/grid/CreateForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/admin/campaigns/grid/CreateForm.tsx b/src/components/admin/campaigns/grid/CreateForm.tsx index f4251a089..54f58a124 100644 --- a/src/components/admin/campaigns/grid/CreateForm.tsx +++ b/src/components/admin/campaigns/grid/CreateForm.tsx @@ -65,7 +65,7 @@ const validationSchema: yup.SchemaOf = yup .shape({ title: yup.string().trim().min(10).max(200).required(), slug: yup.string().trim().min(10).max(200).optional(), - description: yup.string().trim().min(50).max(60000).required(), + description: yup.string().trim().min(50).required(), targetAmount: yup.number().integer().positive().required(), allowDonationOnComplete: yup.bool().optional(), campaignTypeId: yup.string().uuid().required(), From 542d88a1ab32c453c0de058843d9a648b6f292c5 Mon Sep 17 00:00:00 2001 From: Alexander Petkov Date: Wed, 24 Apr 2024 18:25:16 +0300 Subject: [PATCH 2/2] refactor: Replace qull editor with innerHTML for reading campaign description The Quill editor shows incosistency when reading the data(adds unnecessary spaces, breaks formating etc.) --- package.json | 4 +- src/common/util/htmlUtils.ts | 2 +- .../client/campaigns/CampaignDetails.tsx | 13 +- src/components/common/QuillStyleWrapper.tsx | 38 ++- yarn.lock | 222 +++++++++++++++++- 5 files changed, 249 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 05da1d0a5..7fc966624 100644 --- a/package.json +++ b/package.json @@ -51,9 +51,10 @@ "chartjs-plugin-annotation": "^3.0.1", "chartjs-plugin-datalabels": "^2.2.0", "date-fns": "2.24.0", - "dompurify": "^3.0.3", "formik": "2.2.9", + "fs": "^0.0.1-security", "i18next": "^23.5.1", + "isomorphic-dompurify": "^2.7.0", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "mobx": "6.3.2", @@ -94,7 +95,6 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@types/cookie": "^0.4.1", - "@types/dompurify": "^3", "@types/lodash.truncate": "^4.4.7", "@types/lru-cache": "^5.1.1", "@types/node": "14.14.37", diff --git a/src/common/util/htmlUtils.ts b/src/common/util/htmlUtils.ts index f34910363..99a118e1c 100644 --- a/src/common/util/htmlUtils.ts +++ b/src/common/util/htmlUtils.ts @@ -1,4 +1,4 @@ -import DOMPurify from 'dompurify' +import DOMPurify from 'isomorphic-dompurify' export function sanitizeHTML(htmlContent: string): string { return DOMPurify.sanitize(htmlContent, { ADD_TAGS: ['iframe'] }) diff --git a/src/components/client/campaigns/CampaignDetails.tsx b/src/components/client/campaigns/CampaignDetails.tsx index c26baf3e3..d8441bcf5 100644 --- a/src/components/client/campaigns/CampaignDetails.tsx +++ b/src/components/client/campaigns/CampaignDetails.tsx @@ -28,8 +28,9 @@ import { moneyPublic } from 'common/util/money' import CampaignPublicExpensesChart from './CampaignPublicExpensesChart' import EmailIcon from '@mui/icons-material/Email' import RenderCampaignSubscribeModal from '../notifications/CampaignSubscribeModal' +import { QuillStypeWrapper } from 'components/common/QuillStyleWrapper' +import { sanitizeHTML } from 'common/util/htmlUtils' -const ReactQuill = dynamic(() => import('react-quill'), { ssr: false }) const CampaignNewsSection = dynamic(() => import('./CampaignNewsSection'), { ssr: false }) const PREFIX = 'CampaignDetails' @@ -128,6 +129,7 @@ export default function CampaignDetails({ campaign }: Props) { const canEditCampaign = useCanEditCampaign(campaign.slug) const { data: expensesList } = useCampaignApprovedExpensesList(campaign.slug) const totalExpenses = expensesList?.reduce((acc, expense) => acc + expense.amount, 0) + const sanitizedDescription = sanitizeHTML(campaign.description) return ( @@ -155,7 +157,14 @@ export default function CampaignDetails({ campaign }: Props) { - + + {/*Temp: Surpress hydratation warning until the reason for the fail is found*/} + + diff --git a/src/components/common/QuillStyleWrapper.tsx b/src/components/common/QuillStyleWrapper.tsx index 5fd76b003..da692972b 100644 --- a/src/components/common/QuillStyleWrapper.tsx +++ b/src/components/common/QuillStyleWrapper.tsx @@ -6,10 +6,18 @@ export const QuillStypeWrapper = styled(Grid)(({ theme }) => ({ maxWidth: '100%', }, - ['p']: { - fontSize: theme.spacing(2), - fontWeight: 400, - lineHeight: theme.spacing(2.85), + ['p, span, a']: { + fontSize: theme.typography.pxToRem(16), + lineHeight: theme.spacing(4), + fontWeight: 500, + paddingLeft: '0', + paddingRight: '0', + fontFamily: theme.typography.fontFamily, + }, + + ['strong']: { + fontWeight: 700, + fontSize: theme.typography.pxToRem(16), }, ['.ql-editor, .ql-video']: { @@ -21,12 +29,11 @@ export const QuillStypeWrapper = styled(Grid)(({ theme }) => ({ marginInline: 'auto', }, - ['.ql-editor, blockquote, .ql-editor h1, .ql-editor h2, .ql-editor h3, .ql-editor h4, .ql-editor h5, .ql-editor h6, .ql-editor ol, .ql-editor p, .ql-editor pre, .ql-editor ul']: - { - margin: 0, - padding: 0, - counterReset: 'list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9', - }, + ['blockquote, h1, h2, h3,h4, h5,h6, ol, p, pre, ul']: { + margin: 0, + padding: 0, + counterReset: 'list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9', + }, ['.ql-editor ol, .ql-editor ul']: { paddingLeft: '1.5em', @@ -77,7 +84,14 @@ export const QuillStypeWrapper = styled(Grid)(({ theme }) => ({ fontSize: theme.typography.pxToRem(24), }, - ['.ql-bubble .ql-editor a ']: { - textDecoration: 'none', + ['a']: { + textDecoration: 'underline', + color: 'rgb(17, 85, 204)', + }, + ['ul']: { + listStyle: 'inside', + }, + ['ul, ol']: { + paddingLeft: '1.5em', }, })) diff --git a/yarn.lock b/yarn.lock index 70162d255..e038ae7ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3847,12 +3847,12 @@ __metadata: languageName: node linkType: hard -"@types/dompurify@npm:^3": - version: 3.0.2 - resolution: "@types/dompurify@npm:3.0.2" +"@types/dompurify@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/dompurify@npm:3.0.5" dependencies: "@types/trusted-types": "*" - checksum: dc017e16a46bcc77086af7d4dc5d2bf4102f16bf1a11b2937e90380da50e77716a2a608ff52990b1293250fefc2ad7593a1378fe07e3a7e21f200d702f0a7878 + checksum: ffc34eca6a4536e1c8c16a47cce2623c5a118a9785492e71230052d92933ff096d14326ff449031e8dfaac509413222372d8f2b28786a13159de6241df716185 languageName: node linkType: hard @@ -4508,6 +4508,15 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: ^4.3.4 + checksum: 51c158769c5c051482f9ca2e6e1ec085ac72b5a418a9b31b4e82fe6c0a6699adb94c1c42d246699a587b3335215037091c79e0de512c516f73b6ea844202f037 + languageName: node + linkType: hard + "agentkeepalive@npm:^4.2.1": version: 4.3.0 resolution: "agentkeepalive@npm:4.3.0" @@ -5821,6 +5830,15 @@ __metadata: languageName: node linkType: hard +"cssstyle@npm:^4.0.1": + version: 4.0.1 + resolution: "cssstyle@npm:4.0.1" + dependencies: + rrweb-cssom: ^0.6.0 + checksum: 4b2fdd81c565b1f8f24a792f85d3a19269a2f201e731c3fe3531d7fc78b4bc6b31906ed17aba7edba7b1c8b7672574fc6c09fe925556da3a9a9458dbf8c4fa22 + languageName: node + linkType: hard + "csstype@npm:^3.0.2, csstype@npm:^3.1.2": version: 3.1.2 resolution: "csstype@npm:3.1.2" @@ -5856,6 +5874,16 @@ __metadata: languageName: node linkType: hard +"data-urls@npm:^5.0.0": + version: 5.0.0 + resolution: "data-urls@npm:5.0.0" + dependencies: + whatwg-mimetype: ^4.0.0 + whatwg-url: ^14.0.0 + checksum: 5c40568c31b02641a70204ff233bc4e42d33717485d074244a98661e5f2a1e80e38fe05a5755dfaf2ee549f2ab509d6a3af2a85f4b2ad2c984e5d176695eaf46 + languageName: node + linkType: hard + "date-fns@npm:2.24.0": version: 2.24.0 resolution: "date-fns@npm:2.24.0" @@ -5908,7 +5936,7 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.4.2": +"decimal.js@npm:^10.4.2, decimal.js@npm:^10.4.3": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae @@ -6272,10 +6300,10 @@ __metadata: languageName: node linkType: hard -"dompurify@npm:^3.0.3": - version: 3.0.4 - resolution: "dompurify@npm:3.0.4" - checksum: 098de639595861127c644df48932f829d35860058365ea46cbf54f9a93b309774da3c4568198a6daaf68efd1593ed09ff842c0c4e848991e09a1d51e32eab33e +"dompurify@npm:^3.1.0": + version: 3.1.0 + resolution: "dompurify@npm:3.1.0" + checksum: 06fc76607cd076e394b2ea5479ab6f0407b8fedb6877ae95e94207b878365e5e1cd914055dacce152a5f419818afb8d4cd284b780246cf35363f0747c179a0ba languageName: node linkType: hard @@ -7419,6 +7447,13 @@ __metadata: languageName: node linkType: hard +"fs@npm:^0.0.1-security": + version: 0.0.1-security + resolution: "fs@npm:0.0.1-security" + checksum: 53c6230e1faae9fa32c1df82c16a84b51b1243d20f3da2b64bd110bb472b73b9185169b703e008356e3cdc92d155088b617d9d39a63b5227a30b3621baad7f5d + languageName: node + linkType: hard + "fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" @@ -8076,6 +8111,15 @@ __metadata: languageName: node linkType: hard +"html-encoding-sniffer@npm:^4.0.0": + version: 4.0.0 + resolution: "html-encoding-sniffer@npm:4.0.0" + dependencies: + whatwg-encoding: ^3.1.1 + checksum: 3339b71dab2723f3159a56acf541ae90a408ce2d11169f00fe7e0c4663d31d6398c8a4408b504b4eec157444e47b084df09b3cb039c816660f0dd04846b8957d + languageName: node + linkType: hard + "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -8158,6 +8202,16 @@ __metadata: languageName: node linkType: hard +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: ^7.1.0 + debug: ^4.3.4 + checksum: 670858c8f8f3146db5889e1fa117630910101db601fff7d5a8aa637da0abedf68c899f03d3451cac2f83bcc4c3d2dabf339b3aa00ff8080571cceb02c3ce02f3 + languageName: node + linkType: hard + "https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -8168,6 +8222,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.2": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" + dependencies: + agent-base: ^7.0.2 + debug: 4 + checksum: daaab857a967a2519ddc724f91edbbd388d766ff141b9025b629f92b9408fc83cee8a27e11a907aede392938e9c398e240d643e178408a59e4073539cde8cfe9 + languageName: node + linkType: hard + "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" @@ -8856,6 +8920,17 @@ __metadata: languageName: node linkType: hard +"isomorphic-dompurify@npm:^2.7.0": + version: 2.7.0 + resolution: "isomorphic-dompurify@npm:2.7.0" + dependencies: + "@types/dompurify": ^3.0.5 + dompurify: ^3.1.0 + jsdom: ^24.0.0 + checksum: 95a16e89e9bac48445d025003506591cea7033b5a8668091699a528beeb021c2fc4397092b59f6dfeeada1ffc7b00ce51c19682e77ee00714a3d7cd14f195294 + languageName: node + linkType: hard + "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.0 resolution: "istanbul-lib-coverage@npm:3.2.0" @@ -9465,6 +9540,40 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^24.0.0": + version: 24.0.0 + resolution: "jsdom@npm:24.0.0" + dependencies: + cssstyle: ^4.0.1 + data-urls: ^5.0.0 + decimal.js: ^10.4.3 + form-data: ^4.0.0 + html-encoding-sniffer: ^4.0.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.2 + is-potential-custom-element-name: ^1.0.1 + nwsapi: ^2.2.7 + parse5: ^7.1.2 + rrweb-cssom: ^0.6.0 + saxes: ^6.0.0 + symbol-tree: ^3.2.4 + tough-cookie: ^4.1.3 + w3c-xmlserializer: ^5.0.0 + webidl-conversions: ^7.0.0 + whatwg-encoding: ^3.1.1 + whatwg-mimetype: ^4.0.0 + whatwg-url: ^14.0.0 + ws: ^8.16.0 + xml-name-validator: ^5.0.0 + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + checksum: 180cf672c1f5e4375fd831b6990c453b4c22b540619abe7a0a3ed0d18eca1171dea9f25739bc06dfea26d1c0d71c7ac26e62fc9a2d9b1657003fc8fd1bf6f9f4 + languageName: node + linkType: hard + "jsesc@npm:^2.5.1": version: 2.5.2 resolution: "jsesc@npm:2.5.2" @@ -11270,6 +11379,13 @@ __metadata: languageName: node linkType: hard +"nwsapi@npm:^2.2.7": + version: 2.2.9 + resolution: "nwsapi@npm:2.2.9" + checksum: 3ab2bc47d5507a76e2fdee5aae7ea2875c6def912d0401126cad3e39825a7decb7a02622810c855a7902bd31e917e606b37882dca12b0ae54b4d3b70275de927 + languageName: node + linkType: hard + "oauth@npm:^0.9.15": version: 0.9.15 resolution: "oauth@npm:0.9.15" @@ -11603,7 +11719,7 @@ __metadata: languageName: node linkType: hard -"parse5@npm:^7.0.0, parse5@npm:^7.1.1": +"parse5@npm:^7.0.0, parse5@npm:^7.1.1, parse5@npm:^7.1.2": version: 7.1.2 resolution: "parse5@npm:7.1.2" dependencies: @@ -11746,7 +11862,6 @@ __metadata: "@testing-library/react": ^13.4.0 "@tryghost/content-api": ^1.11.4 "@types/cookie": ^0.4.1 - "@types/dompurify": ^3 "@types/lodash.truncate": ^4.4.7 "@types/lru-cache": ^5.1.1 "@types/node": 14.14.37 @@ -11769,7 +11884,6 @@ __metadata: chartjs-plugin-datalabels: ^2.2.0 date-fns: 2.24.0 depcheck: ^1.4.3 - dompurify: ^3.0.3 eslint: ^8.44.0 eslint-config-next: ^13.4.9 eslint-config-prettier: ^8.8.0 @@ -11777,8 +11891,10 @@ __metadata: eslint-plugin-react: ^7.32.2 eslint-plugin-react-hooks: ^4.6.0 formik: 2.2.9 + fs: ^0.0.1-security husky: 7.0.1 i18next: ^23.5.1 + isomorphic-dompurify: ^2.7.0 jest: ^29.6.1 jest-environment-jsdom: ^29.6.1 jwt-decode: ^3.1.2 @@ -12114,6 +12230,13 @@ __metadata: languageName: node linkType: hard +"punycode@npm:^2.3.1": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2 + languageName: node + linkType: hard + "pure-rand@npm:^6.0.0": version: 6.0.2 resolution: "pure-rand@npm:6.0.2" @@ -12933,6 +13056,13 @@ __metadata: languageName: node linkType: hard +"rrweb-cssom@npm:^0.6.0": + version: 0.6.0 + resolution: "rrweb-cssom@npm:0.6.0" + checksum: 182312f6e4f41d18230ccc34f14263bc8e8a6b9d30ee3ec0d2d8e643c6f27964cd7a8d638d4a00e988d93e8dc55369f4ab5a473ccfeff7a8bab95b36d2b5499c + languageName: node + linkType: hard + "run-applescript@npm:^5.0.0": version: 5.0.0 resolution: "run-applescript@npm:5.0.0" @@ -14135,7 +14265,7 @@ __metadata: languageName: node linkType: hard -"tough-cookie@npm:^4.1.2": +"tough-cookie@npm:^4.1.2, tough-cookie@npm:^4.1.3": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3" dependencies: @@ -14156,6 +14286,15 @@ __metadata: languageName: node linkType: hard +"tr46@npm:^5.0.0": + version: 5.0.0 + resolution: "tr46@npm:5.0.0" + dependencies: + punycode: ^2.3.1 + checksum: 8d8b021f8e17675ebf9e672c224b6b6cfdb0d5b92141349e9665c14a2501c54a298d11264bbb0b17b447581e1e83d4fc3c038c929f3d210e3964d4be47460288 + languageName: node + linkType: hard + "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -14717,6 +14856,15 @@ __metadata: languageName: node linkType: hard +"w3c-xmlserializer@npm:^5.0.0": + version: 5.0.0 + resolution: "w3c-xmlserializer@npm:5.0.0" + dependencies: + xml-name-validator: ^5.0.0 + checksum: 593acc1fdab3f3207ec39d851e6df0f3fa41a36b5809b0ace364c7a6d92e351938c53424a7618ce8e0fbaffee8be2e8e070a5734d05ee54666a8bdf1a376cc40 + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -14801,6 +14949,15 @@ __metadata: languageName: node linkType: hard +"whatwg-encoding@npm:^3.1.1": + version: 3.1.1 + resolution: "whatwg-encoding@npm:3.1.1" + dependencies: + iconv-lite: 0.6.3 + checksum: f75a61422421d991e4aec775645705beaf99a16a88294d68404866f65e92441698a4f5b9fa11dd609017b132d7b286c3c1534e2de5b3e800333856325b549e3c + languageName: node + linkType: hard + "whatwg-mimetype@npm:^3.0.0": version: 3.0.0 resolution: "whatwg-mimetype@npm:3.0.0" @@ -14808,6 +14965,13 @@ __metadata: languageName: node linkType: hard +"whatwg-mimetype@npm:^4.0.0": + version: 4.0.0 + resolution: "whatwg-mimetype@npm:4.0.0" + checksum: f97edd4b4ee7e46a379f3fb0e745de29fe8b839307cc774300fd49059fcdd560d38cb8fe21eae5575b8f39b022f23477cc66e40b0355c2851ce84760339cef30 + languageName: node + linkType: hard + "whatwg-url@npm:^11.0.0": version: 11.0.0 resolution: "whatwg-url@npm:11.0.0" @@ -14818,6 +14982,16 @@ __metadata: languageName: node linkType: hard +"whatwg-url@npm:^14.0.0": + version: 14.0.0 + resolution: "whatwg-url@npm:14.0.0" + dependencies: + tr46: ^5.0.0 + webidl-conversions: ^7.0.0 + checksum: 4b5887e50f786583bead70916413e67a381d2126899b9eb5c67ce664bba1e7ec07cdff791404581ce73c6190d83c359c9ca1d50711631217905db3877dec075c + languageName: node + linkType: hard + "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0" @@ -14995,6 +15169,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.16.0": + version: 8.16.0 + resolution: "ws@npm:8.16.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: feb3eecd2bae82fa8a8beef800290ce437d8b8063bdc69712725f21aef77c49cb2ff45c6e5e7fce622248f9c7abaee506bae0a9064067ffd6935460c7357321b + languageName: node + linkType: hard + "ws@npm:~8.11.0": version: 8.11.0 resolution: "ws@npm:8.11.0" @@ -15017,6 +15206,13 @@ __metadata: languageName: node linkType: hard +"xml-name-validator@npm:^5.0.0": + version: 5.0.0 + resolution: "xml-name-validator@npm:5.0.0" + checksum: 86effcc7026f437701252fcc308b877b4bc045989049cfc79b0cc112cb365cf7b009f4041fab9fb7cd1795498722c3e9fe9651afc66dfa794c16628a639a4c45 + languageName: node + linkType: hard + "xmlchars@npm:^2.2.0": version: 2.2.0 resolution: "xmlchars@npm:2.2.0"