diff --git a/package-lock.json b/package-lock.json index c1011c5a..e5a2187e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.0.0", "dependencies": { "@reduxjs/toolkit": "^2.2.3", + "html2canvas": "^1.4.1", + "jspdf": "^3.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.1" @@ -325,6 +327,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "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" + } + }, "node_modules/@babel/template": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", @@ -1207,12 +1218,25 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "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/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", "devOptional": true }, + "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": "18.2.79", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", @@ -1232,6 +1256,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.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", @@ -1486,6 +1517,15 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "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/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1576,6 +1616,26 @@ } ] }, + "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": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -1617,6 +1677,18 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/core-js": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1631,6 +1703,15 @@ "node": ">= 8" } }, + "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/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1757,6 +1838,16 @@ "node": ">=6.0.0" } }, + "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/electron-to-chromium": { "version": "1.4.748", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.748.tgz", @@ -2299,6 +2390,17 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "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/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -2308,6 +2410,12 @@ "reusify": "^1.0.4" } }, + "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/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2621,6 +2729,19 @@ "node": ">= 0.4" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -2694,6 +2815,12 @@ "node": ">= 0.4" } }, + "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/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -3115,6 +3242,23 @@ "node": ">=6" } }, + "node_modules/jspdf": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.3.tgz", + "integrity": "sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.9", + "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/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -3408,6 +3552,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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", @@ -3453,6 +3603,13 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "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/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -3545,6 +3702,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/react": { "version": "18.3.0", "resolved": "https://registry.npmjs.org/react/-/react-18.3.0.tgz", @@ -3643,6 +3810,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.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -3702,6 +3876,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": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -3907,6 +4091,16 @@ "node": ">=0.10.0" } }, + "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/string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", @@ -4030,6 +4224,25 @@ "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/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/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4204,6 +4417,15 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "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/vite": { "version": "5.2.10", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", diff --git a/package.json b/package.json index e34856cb..71c3ff8b 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.2.3", + "html2canvas": "^1.4.1", + "jspdf": "^3.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.1" diff --git a/src/ConferenceEvent.css b/src/ConferenceEvent.css index d69f2a9d..d06ea39b 100644 --- a/src/ConferenceEvent.css +++ b/src/ConferenceEvent.css @@ -1,338 +1,469 @@ /* Venue selection styles */ .venue_container { - text-align: center; - display: flex; - flex-direction: column; - gap: 40px; - align-items: center; - justify-content: center; - width: 80vw; - padding: 20px; - border-radius: 10px; - margin-left: -180px; - font-size: 24px; - } - - .venue_selection,.addons_selection , .meal_selection { - display: flex; - flex-wrap: wrap; - gap: 30px; - width: 90vw; - margin-left: 250px; - } - - .venue_main { - display: flex; - flex-direction: column; - align-items: center; - gap: 10px; - border: 1px solid lightgrey; - border-radius: 10px; - padding: 10px; - background-color: #f9f9f9; - color: #333; - width: 300px; - } - .text h1{ - width: 900px; - font-size: 40px; - background-color: #133b6a; - color: white; - width:990px; - height: 70px; - margin-left: 240px; - display: flex; - align-items: center; - justify-content: center; - - } - .venue_main .text { - font-size: 30px; - color: #333; - } - .quantity-value { - margin: 0 10px; - } - .main_container{ - display: flex; - } - .items-information { - display: flex; - flex-direction: column; - gap: 90px; - margin-top: 100px; - width: 100vw; - align-items: center; - justify-content: center; - - } - .meal_item { - display: flex; + text-align: center; + display: flex; + flex-direction: column; + gap: 40px; + align-items: center; + justify-content: center; + width: 80vw; + padding: 20px; + border-radius: 10px; + margin-left: -180px; + font-size: 24px; +} + +.venue_selection, +.addons_selection, +.meal_selection { + display: flex; + flex-wrap: wrap; + gap: 30px; + width: 90vw; + margin-left: 250px; +} + +.venue_main { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + border: 1px solid lightgrey; + border-radius: 10px; + padding: 10px; + background-color: #f9f9f9; + color: #333; + width: 300px; +} +.text h1 { + width: 900px; + font-size: 40px; + background-color: #133b6a; + color: white; + width: 990px; + height: 70px; + margin-left: 240px; + display: flex; + align-items: center; + justify-content: center; +} +.venue_main .text { + font-size: 30px; + color: #333; +} +.quantity-value { + margin: 0 10px; +} +.main_container { + display: flex; +} +.items-information { + display: flex; + flex-direction: column; + gap: 90px; + margin-top: 100px; + width: 100vw; + align-items: center; + justify-content: center; +} +.meal_item { + display: flex; + flex-direction: column; + gap: 10px; +} +.total_cost { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; + font-size: 30px; + color: #333; + background-color: #f9f9f9; + border-radius: 10px; + padding: 10px; + width: 400px; + margin-top: 15px; + margin-left: 190px; +} + +.av_data { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + padding: 10px; + border: 1px solid lightgrey; + border-radius: 10px; + background-color: #f9f9f9; + color: #000; +} + +.input-container { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + font-size: 20px; +} +.input-container input { + width: 100px; + height: 30px; + border-radius: 5px; + border: 1px solid lightgrey; + padding: 13px; +} +.meal_selection { + display: flex; + flex-wrap: wrap; + width: 600px; + align-items: center; + justify-content: flex-start; + gap: 20px; + margin-left: 280px; +} +.meal_selection input[type="checkbox"] { + width: 20px; + height: 20px; + padding: 5px; +} +.meal_selection label { + font-size: 25px; +} +.meal_item .inner { + display: flex; + flex-direction: row; +} +.meal_item .inner input { + width: 100px; + height: 30px; + border-radius: 5px; + border: 1px solid lightgrey; + padding: 5px; +} +.meal_item .meal_cost { + margin-left: 20px; + display: flex; + flex-direction: column; + font-size: 25px; + margin-left: 40px; +} +.venue_main .img img { + width: 100%; + height: 200px; + object-fit: cover; + border-radius: 10px; +} +.display_box1 { + margin-top: 20px; + overflow-y: auto; + height: 300px; + scrollbar-width: thin; + scrollbar-color: #b7b4b4 transparent; +} + +.display_box1::-webkit-scrollbar { + width: 8px; /* For Chrome, Safari, and Opera */ +} + +.display_box1::-webkit-scrollbar-track { + background-color: transparent; /* For Chrome, Safari, and Opera */ +} + +.display_box1::-webkit-scrollbar-thumb { + background-color: #ffffff; /* For Chrome, Safari, and Opera */ +} + +.display_box1 { + padding-left: 20px; +} +.addons_btn { + display: flex; + align-items: center; + justify-content: center; +} +.btn-success { + display: flex; + align-items: center; + justify-content: center; + background-color: #5291d9; + color: black; + border: none; + width: 10px; + height: 30px; + border-radius: 5px; + cursor: pointer; +} +.btn-warning { + background-color: #52d7d9; + display: flex; + align-items: center; + justify-content: center; + color: black; + width: 10px; + height: 30px; + border: none; + border-radius: 5px; + cursor: pointer; +} + +.input-container .input_box5 { + height: 40px; + width: 200px; + font-size: 20px; +} + +.items_view { + font-size: 20px; +} +.table_item_data { + width: 70vw; + border-collapse: collapse; + margin-left: -6px; +} + +.table_item_data th, +.table_item_data td { + padding: 8px; + border: 1px solid #ddd; + font-size: 23px; +} + +.table_item_data th { + background-color: #f2f2f2; +} + +.table_item_data tbody tr:nth-child(even) { + background-color: #f9f9f9; +} + +.table_item_data tbody tr:hover { + background-color: #f2f2f2; +} + +.table_item_data tbody tr:first-child:hover { + background-color: transparent; +} +/* 🌐 Navbar Container */ +.navbar_event_conference { + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 99; + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 5%; + background-color: #133b6a; + color: white; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); +} + +/* 🏢 Company Logo */ +.company_logo { + font-size: 1.8rem; + color: #efc16b; + font-weight: 700; + letter-spacing: 0.5px; + text-transform: capitalize; +} + +/* 🧭 Left Navbar Section */ +.left_navbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 4rem; + width: 60%; +} + +/* 🔗 Navigation Links */ +.nav_links { + display: flex; + gap: 3rem; + align-items: center; +} + +.nav_links a { + text-decoration: none; + color: white; + font-size: 1.1rem; + font-weight: 500; + transition: color 0.3s ease, transform 0.3s ease; +} + +.nav_links a:hover { + color: #efc16b; + transform: translateY(-2px); +} + +/* 🟡 Show Details Button */ +.details_button { + padding: 0.6rem 1.2rem; + background-color: #efc16b; + color: #133b6a; + font-size: 1rem; + font-weight: 600; + border: none; + border-radius: 0.5rem; + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease; +} + +.details_button:hover { + background-color: #ffda85; + transform: scale(1.05); +} + +/* Disabled State */ +.btn-disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* 📱 Responsive Design */ +@media (max-width: 1024px) { + .navbar_event_conference { flex-direction: column; - gap: 10px; - } - .total_cost { - display: flex; - justify-content: center; - align-items: center; - gap: 20px; - font-size: 30px; - color: #333; - background-color: #f9f9f9; - border-radius: 10px; - padding: 10px; - width: 400px; - margin-top: 15px; - margin-left: 190px; + align-items: flex-start; + padding: 1rem 4%; } - - .av_data { - display: flex; + + .left_navbar { + width: 100%; flex-direction: column; - align-items: center; - gap: 20px; - padding: 10px; - border: 1px solid lightgrey; - border-radius: 10px; - background-color: #f9f9f9; - color: #000; + align-items: flex-start; + gap: 1.5rem; + margin-top: 1rem; } - .input-container{ - display: flex; - align-items: center; - justify-content: center; - gap: 10px; - font-size: 20px; - } - .input-container input { - width: 100px; - height: 30px; - border-radius: 5px; - border: 1px solid lightgrey; - padding: 13px; - } - .meal_selection { - display: flex; - flex-wrap: wrap; - width: 600px; - align-items: center; - justify-content: flex-start; - gap: 20px; - margin-left: 280px; - } - .meal_selection input[type="checkbox"] { - width: 20px; - height: 20px; - padding: 5px; - } - .meal_selection label { - font-size: 25px; - } - .meal_item .inner { - display: flex; - flex-direction: row; - } - .meal_item .inner input { - width: 100px; - height: 30px; - border-radius: 5px; - border: 1px solid lightgrey; - padding: 5px; - } - .meal_item .meal_cost { - margin-left: 20px; - display: flex; + .nav_links { flex-direction: column; - font-size: 25px; - margin-left: 40px; - } - .venue_main .img img { width: 100%; - height: 200px; - object-fit: cover; - border-radius: 10px; - } - .display_box1 { - margin-top: 20px; - overflow-y: auto; - height: 300px; - scrollbar-width: thin; - scrollbar-color: #b7b4b4 transparent; + gap: 1rem; } - - .display_box1::-webkit-scrollbar { - width: 8px; /* For Chrome, Safari, and Opera */ - - } - - .display_box1::-webkit-scrollbar-track { - background-color: transparent; /* For Chrome, Safari, and Opera */ - - } - - .display_box1::-webkit-scrollbar-thumb { - background-color: #ffffff; /* For Chrome, Safari, and Opera */ + + .nav_links a { + font-size: 1rem; } - - .display_box1 { - padding-left: 20px; + + .details_button { + align-self: center; + width: 50%; + text-align: center; } - .addons_btn { + /* 🔘 Container Styling */ + .button_container { display: flex; align-items: center; justify-content: center; - + gap: 1rem; /* spacing between buttons and count */ + flex-wrap: wrap; + width: 100%; + max-width: 250px; + margin: 0 auto; } - .btn-success { - display: flex; - align-items: center; - justify-content: center; - background-color: #5291D9; - color: black; + + /* ➕➖ Buttons Base Style */ + .button_container button { border: none; - width: 10px; - height: 30px; - border-radius: 5px; + border-radius: 0.5rem; + padding: 0.5rem 1rem; + font-size: 1.2rem; + font-weight: 600; cursor: pointer; + transition: all 0.25s ease; + min-width: 2.5rem; } + + /* ⚠️ Warning Button (Minus) */ .btn-warning { - background-color: #52D7D9; - display: flex; - align-items: center; - justify-content: center; - color: black; - width: 10px; - height: 30px; - border: none; - border-radius: 5px; - cursor: pointer; - } - - .input-container .input_box5{ - height: 40px; - width: 200px; - font-size: 20px; + background-color: #ffae42; + color: #fff; } - - .items_view{ - font-size: 20px; - } - .table_item_data { - width: 70vw; - border-collapse: collapse; - margin-left: -6px; - + + .btn-warning:hover:not(.btn-disabled) { + background-color: #ff9800; + transform: scale(1.05); } - - .table_item_data th, - .table_item_data td { - padding: 8px; - border: 1px solid #ddd; - font-size: 23px; - + + /* ✅ Success Button (Plus) */ + .btn-success { + background-color: #4caf50; + color: white; } - - .table_item_data th { - background-color: #f2f2f2; + + .btn-success:hover:not(.btn-disabled) { + background-color: #43a047; + transform: scale(1.05); } - - .table_item_data tbody tr:nth-child(even) { - background-color: #f9f9f9; + + /* 🧮 Count Display */ + .selected_count { + font-size: 1.2rem; + font-weight: 700; + color: #133b6a; + background-color: #f4f4f4; + border-radius: 0.4rem; + padding: 0.3rem 0.8rem; + min-width: 2rem; + text-align: center; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.1); } - - .table_item_data tbody tr:hover { - background-color: #f2f2f2; + + /* 🚫 Disabled Buttons */ + .btn-disabled { + opacity: 0.6; + cursor: not-allowed; + pointer-events: none; + transform: none !important; } - - .table_item_data tbody tr:first-child:hover { - background-color: transparent; + + /* 📱 Responsive Design */ + @media (max-width: 600px) { + .button_container { + gap: 0.7rem; + max-width: 200px; + } + + .button_container button { + padding: 0.4rem 0.8rem; + font-size: 1rem; + } + + .selected_count { + font-size: 1rem; + padding: 0.2rem 0.6rem; + } } - navbar { - display: flex; - justify-content: space-between; - align-items: center; - padding: 20px 20px; - background-color:#133b6a; - color: white; - width: 100vw; +} + +/* 📲 Small Devices (Phones) */ +@media (max-width: 600px) { + .navbar_event_conference { + padding: 0.8rem 3%; } - + .company_logo { - font-size: 30px; - color: #EFC16B; - font-weight: 700; - } - .nav_links{ - display: flex; - gap: 170px; - } - .left_navbar{ - width: 60vw; - display: flex; - gap: 180px; - - } - .nav_links a { - text-decoration: none; - color: white; - margin-right: 20px; - transition: all 0.3s ease; - font-size: 25px; + font-size: 1.4rem; + text-align: center; + width: 100%; } - - .nav_links a:hover { - color: #ff9900; + + .left_navbar { + width: 100%; + align-items: center; + text-align: center; } - .button_container{ - /* background-color: red; */ - width:200px ; - display: flex; - gap: 20px; + + .nav_links { + flex-direction: column; + gap: 0.8rem; } + .details_button { - padding: 8px 16px; - background-color: #EFC16B; - color: black; - /* border: 1px solid white; */ - font-size: 20px; - border-radius: 5px; - cursor: pointer; - transition: all 0.3s ease; - /* background-color: transparent; */ - } - - - .navbar_event_conference{ - position: fixed; - top: 1px; - z-index: 99; + width: 70%; + padding: 0.5rem 1rem; + font-size: 0.95rem; } - .btn-disabled { - opacity: 0.5; /* Reduce opacity to visually indicate disabled state */ - cursor: not-allowed; /* Change cursor to indicate that the button is not clickable */ - } - @media (max-width: 700px) { - navbar { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 20px 20px; - background-color: #133b6a; - color: white; - width: 100vw; - } - .nav_links { - display: flex; - flex-direction: column; - gap: 20px; - } - .left_navbar { - width: 100%; - display: flex; - justify-content: center; - gap: 0; - } - } diff --git a/src/ConferenceEvent.jsx b/src/ConferenceEvent.jsx index 612a4648..92883d8e 100644 --- a/src/ConferenceEvent.jsx +++ b/src/ConferenceEvent.jsx @@ -1,20 +1,21 @@ -import React, { useState } from "react"; +import { useState } from "react"; import "./ConferenceEvent.css"; import TotalCost from "./TotalCost"; +import { toggleMealSelection } from "./mealsSlice"; +import { incrementAvQuantity, decrementAvQuantity } from "./avSlice"; import { useSelector, useDispatch } from "react-redux"; import { incrementQuantity, decrementQuantity } from "./venueSlice"; const ConferenceEvent = () => { const [showItems, setShowItems] = useState(false); const [numberOfPeople, setNumberOfPeople] = useState(1); const venueItems = useSelector((state) => state.venue); + const avItems = useSelector((state) => state.av); + const mealsItems = useSelector((state) => state.meals); const dispatch = useDispatch(); const remainingAuditoriumQuantity = 3 - venueItems.find(item => item.name === "Auditorium Hall (Capacity:200)").quantity; - const handleToggleItems = () => { - console.log("handleToggleItems called"); - setShowItems(!showItems); - }; + const handleAddToCart = (index) => { if (venueItems[index].name === "Auditorium Hall (Capacity:200)" && venueItems[index].quantity >= 3) { @@ -29,35 +30,111 @@ const ConferenceEvent = () => { } }; const handleIncrementAvQuantity = (index) => { - }; + dispatch(incrementAvQuantity(index)); +}; - const handleDecrementAvQuantity = (index) => { - }; +const handleDecrementAvQuantity = (index) => { + dispatch(decrementAvQuantity(index)); +}; - const handleMealSelection = (index) => { - - }; +const handleMealSelection = (index) => { + const item = mealsItems[index]; + if (item.selected && item.type === "mealForPeople") { + // Ensure numberOfPeople is set before toggling selection + const newNumberOfPeople = item.selected ? numberOfPeople : 0; + dispatch(toggleMealSelection(index, newNumberOfPeople)); + } + else { + dispatch(toggleMealSelection(index)); + } +}; - const getItemsFromTotalCost = () => { - const items = []; - }; +const getItemsFromTotalCost = () => { + const items = []; + venueItems.forEach((item) => { + if (item.quantity > 0) { + items.push({ ...item, type: "venue" }); + } + }); + avItems.forEach((item) => { + if ( + item.quantity > 0 && + !items.some((i) => i.name === item.name && i.type === "av") + ) { + items.push({ ...item, type: "av" }); + } + }); + mealsItems.forEach((item) => { + if (item.selected) { + const itemForDisplay = { ...item, type: "meals" }; + if (item.numberOfPeople) { + itemForDisplay.numberOfPeople = numberOfPeople; + } + items.push(itemForDisplay); + } + }); + return items; + }; const items = getItemsFromTotalCost(); const ItemsDisplay = ({ items }) => { - + console.log(items); + return <> +
+ {items.length === 0 &&

No items selected

} + + + + + + + + + + + {items.map((item, index) => ( + + + + + + + ))} + +
NameUnit CostQuantitySubtotal
{item.name}${item.cost} + {item.type === "meals" || item.numberOfPeople + ? ` For ${numberOfPeople} people` + : item.quantity} + {item.type === "meals" || item.numberOfPeople + ? `${item.cost * numberOfPeople}` + : `${item.cost * item.quantity}`} +
+
+ }; const calculateTotalCost = (section) => { let totalCost = 0; if (section === "venue") { - venueItems.forEach((item) => { - totalCost += item.cost * item.quantity; - }); + venueItems.forEach((item) => { + totalCost += item.cost * item.quantity; + }); + } else if (section === "av") { + avItems.forEach((item) => { + totalCost += item.cost * item.quantity; + }); + } else if (section === "meals") { + mealsItems.forEach((item) => { + if (item.selected) { + totalCost += item.cost * numberOfPeople; + } + }); } - return totalCost; - }; + return totalCost; + }; const venueTotalCost = calculateTotalCost("venue"); - +const avTotalCost = calculateTotalCost("av"); +const mealsTotalCost = calculateTotalCost("meals"); const navigateToProducts = (idType) => { if (idType == '#venue' || idType == '#addons' || idType == '#meals') { if (showItems) { // Check if showItems is false @@ -65,6 +142,11 @@ const ConferenceEvent = () => { } } } + const totalCosts = { + venue: venueTotalCost, + av: avTotalCost, + meals: mealsTotalCost, + }; return ( <> @@ -157,10 +239,22 @@ const ConferenceEvent = () => {
- + {avItems.map((item, index) => ( +
+
+ {item.name} +
+
{item.name}
+
${item.cost}
+
+ + {item.quantity} + +
+
+))}
-
Total Cost:
- +
Total Cost: {avTotalCost}
{/* Meal Section */} @@ -173,20 +267,36 @@ const ConferenceEvent = () => {
- +
+ + setNumberOfPeople(parseInt(e.target.value))} + min="1" + /> +
- -
-
Total Cost:
- + {mealsItems.map((item, index) => ( +
+
+ handleMealSelection(index)} + /> + +
+
${item.cost}
+
+ ))} + +
Total Cost: {mealsTotalCost}
) : (
- } /> -
+ } /> + ) } diff --git a/src/TotalCost.css b/src/TotalCost.css index 7e02c96c..387171ad 100644 --- a/src/TotalCost.css +++ b/src/TotalCost.css @@ -1,14 +1,13 @@ .pricing-app { - margin-top: 20px; - /* margin-left: 40vw; */ - width: 100vw; - height: 100vh; - display: flex; - align-items: center; - justify-content: center; + margin-top: 20px; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + position: relative; } - .display_box { text-align: center; box-sizing: border-box; @@ -19,20 +18,46 @@ margin: 0; padding: 55px; width: 80vw; + position: relative; } - .pricing-app .preheading { font-family: dosis, sans-serif; text-transform: uppercase; line-height: 1; margin: 0; - /* padding: 0 0 10px; */ font-size: 25px; } .pricing-app h2 { font-size: 60px; + margin-top: 15px; +} + +/* ✅ PDF Button Styles */ +.pdf-button { + position: absolute; + top: 20px; + right: 25px; + background-color: #007bff; + color: white; + border: none; + border-radius: 8px; + padding: 10px 18px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +} + +.pdf-button:hover { + background-color: #0056b3; + transform: scale(1.05); +} + +.pdf-button:active { + transform: scale(0.98); } .right { diff --git a/src/TotalCost.jsx b/src/TotalCost.jsx index 845abca9..eab69ebc 100644 --- a/src/TotalCost.jsx +++ b/src/TotalCost.jsx @@ -1,24 +1,59 @@ -import React, { useState, useEffect } from 'react'; +import React, { useRef } from "react"; import "./TotalCost.css"; const TotalCost = ({ totalCosts, ItemsDisplay }) => { - + const slipRef = useRef(null); + const total_amount = totalCosts.venue + totalCosts.av + totalCosts.meals; + + const handleDownloadPDF = async () => { + try { + // 🧠 Dynamically import libraries only when needed + const jsPDF = (await import("jspdf")).default; + const html2canvas = (await import("html2canvas")).default; + + const input = slipRef.current; + + // Capture the visible area of the component + const canvas = await html2canvas(input, { + scale: 2, + useCORS: true, + scrollY: -window.scrollY, + }); + + const imgData = canvas.toDataURL("image/png"); + + // PDF setup + const pdf = new jsPDF("p", "mm", "a4"); + const pdfWidth = pdf.internal.pageSize.getWidth(); + const pdfHeight = (canvas.height * pdfWidth) / canvas.width; + + pdf.addImage(imgData, "PNG", 0, 0, pdfWidth, pdfHeight); + pdf.save("Event_Total_Cost.pdf"); + } catch (error) { + console.error("Error generating PDF:", error); + } + }; return (
-
+
-

Total cost for the event

+

Total Cost for the Event

-
+ +

- + ${total_amount}

- -
- -
+ +
+ +
+ +
); diff --git a/src/avSlice.js b/src/avSlice.js index cdd79aac..734f99ab 100644 --- a/src/avSlice.js +++ b/src/avSlice.js @@ -1,22 +1,59 @@ -import { createSlice } from "@reduxjs/toolkit"; + import { createSlice } from "@reduxjs/toolkit"; export const avSlice = createSlice({ name: "av", initialState: [ - + { + img: "", + name: "Projectors", + cost: 200, + quantity: 0, + }, + { + img: "", + name: "Speaker", + cost: 35, + quantity: 0, + }, + { + img: "", + name: "Microphones", + cost: 45, + quantity: 0, + }, + { + img: "", + name: "Whiteboards", + cost: 80, + quantity: 0, + }, + + { + img: "", + name: "Signage", + cost: 80, + quantity: 0, + }, + ], reducers: { incrementAvQuantity: (state, action) => { - + const item = state[action.payload]; + if (item) { + item.quantity++; + } }, decrementAvQuantity: (state, action) => { - + const item = state[action.payload]; + if (item && item.quantity > 0) { + item.quantity--; + } }, }, }); export const { incrementAvQuantity, decrementAvQuantity } = avSlice.actions; -export default avSlice.reducer; +export default avSlice.reducer; \ No newline at end of file diff --git a/src/mealsSlice.js b/src/mealsSlice.js index faf8138a..deea035a 100644 --- a/src/mealsSlice.js +++ b/src/mealsSlice.js @@ -1,17 +1,18 @@ -// mealsSlice.js -import { createSlice } from '@reduxjs/toolkit'; - +import { createSlice } from "@reduxjs/toolkit"; export const mealsSlice = createSlice({ - name: 'meals', + name: "meals", initialState: [ - + { name: "Breakfast", cost: 50, selected: false }, + { name: "High Tea", cost: 25, selected: false }, + { name: "Lunch", cost: 65, selected: false }, + { name: "Dinner", cost: 70, selected: false }, ], reducers: { toggleMealSelection: (state, action) => { + state[action.payload].selected = !state[action.payload].selected; }, }, }); export const { toggleMealSelection } = mealsSlice.actions; - export default mealsSlice.reducer; diff --git a/src/store.js b/src/store.js index f05b9f8f..77e3863b 100644 --- a/src/store.js +++ b/src/store.js @@ -1,9 +1,12 @@ -// store.js -import { configureStore } from '@reduxjs/toolkit'; -import venueReducer from './venueSlice'; +import { configureStore } from "@reduxjs/toolkit"; +import venueReducer from "./venueSlice"; +import avReducer from "./avSlice"; +import mealsReducer from "./mealsSlice"; export default configureStore({ reducer: { venue: venueReducer, + av: avReducer, + meals: mealsReducer, }, });