diff --git a/package.json b/package.json index 632912a..43d44ea 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,15 @@ "@heroicons/react": "^2.2.0", "@reduxjs/toolkit": "^2.4.0", "@tanstack/react-query": "^5.62.2", + "@types/quill": "^2.0.14", "@types/react-redux": "^7.1.34", "axios": "^1.7.9", "jwt-decode": "^4.0.0", + "quill": "^2.0.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.54.1", + "react-quill": "^2.0.0", "react-redux": "^9.1.2", "react-router": "^7.0.2", "redux-persist": "^6.0.0", @@ -38,8 +41,8 @@ "@storybook/react-vite": "^8.4.7", "@storybook/test": "^8.4.7", "@types/jwt-decode": "^3.1.0", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", + "@types/react": "^18.3.14", + "@types/react-dom": "^18.3.2", "@types/redux-persist": "^4.3.1", "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.15.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b288db6..4e5d830 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@tanstack/react-query': specifier: ^5.62.2 version: 5.62.2(react@18.3.1) + '@types/quill': + specifier: ^2.0.14 + version: 2.0.14 '@types/react-redux': specifier: ^7.1.34 version: 7.1.34 @@ -26,6 +29,9 @@ importers: jwt-decode: specifier: ^4.0.0 version: 4.0.0 + quill: + specifier: ^2.0.3 + version: 2.0.3 react: specifier: ^18.3.1 version: 18.3.1 @@ -35,6 +41,9 @@ importers: react-hook-form: specifier: ^7.54.1 version: 7.54.1(react@18.3.1) + react-quill: + specifier: ^2.0.0 + version: 2.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-redux: specifier: ^9.1.2 version: 9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1) @@ -79,10 +88,10 @@ importers: specifier: ^3.1.0 version: 3.1.0 '@types/react': - specifier: ^18.3.12 + specifier: ^18.3.14 version: 18.3.14 '@types/react-dom': - specifier: ^18.3.1 + specifier: ^18.3.2 version: 18.3.2 '@types/redux-persist': specifier: ^4.3.1 @@ -1073,6 +1082,12 @@ packages: '@types/prop-types@15.7.14': resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} + '@types/quill@1.3.10': + resolution: {integrity: sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==} + + '@types/quill@2.0.14': + resolution: {integrity: sha512-zvoXCRnc2Dl8g+7/9VSAmRWPN6oH+MVhTPizmCR+GJCITplZ5VRVzMs4+a/nOE3yzNwEZqylJJrMB07bwbM1/g==} + '@types/react-dom@18.3.2': resolution: {integrity: sha512-Fqp+rcvem9wEnGr3RY8dYNvSQ8PoLqjZ9HLgaPUOjJJD120uDyOxOjc/39M4Kddp9JQCxpGQbnhVQF0C0ncYVg==} @@ -1307,10 +1322,18 @@ packages: resolution: {integrity: sha512-CCKAP2tkPau7D3GE8+V8R6sQubA9R5foIzGp+85EXCVSCivuxBNAWqcpn72PKYiIcqoViv/kcUDpaEIMBVi1lQ==} engines: {node: '>= 0.4'} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + call-bind@1.0.8: resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1361,6 +1384,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1425,6 +1452,10 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + deep-equal@1.1.2: + resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==} + engines: {node: '>= 0.4'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1436,6 +1467,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1485,6 +1520,10 @@ packages: es-module-lexer@1.5.4: resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -1578,13 +1617,28 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eventemitter3@2.0.3: + resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + expect-type@1.1.0: resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} engines: {node: '>=12.0.0'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-diff@1.1.2: + resolution: {integrity: sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -1645,6 +1699,9 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1657,6 +1714,10 @@ packages: resolution: {integrity: sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==} engines: {node: '>= 0.4'} + get-intrinsic@1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + engines: {node: '>= 0.4'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1758,6 +1819,10 @@ packages: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -1786,6 +1851,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} @@ -1851,6 +1920,15 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -1884,6 +1962,10 @@ packages: map-or-similar@1.5.0: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -1948,6 +2030,14 @@ packages: node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -1967,6 +2057,12 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + parchment@1.1.4: + resolution: {integrity: sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==} + + parchment@3.0.0: + resolution: {integrity: sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2058,6 +2154,21 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quill-delta@3.6.3: + resolution: {integrity: sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==} + engines: {node: '>=0.10'} + + quill-delta@5.1.0: + resolution: {integrity: sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==} + engines: {node: '>= 12.0.0'} + + quill@1.3.7: + resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==} + + quill@2.0.3: + resolution: {integrity: sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==} + engines: {npm: '>=8.2.3'} + react-confetti@6.1.0: resolution: {integrity: sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==} engines: {node: '>=10.18'} @@ -2090,6 +2201,12 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-quill@2.0.0: + resolution: {integrity: sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==} + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + react-redux@9.1.2: resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==} peerDependencies: @@ -2151,6 +2268,10 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -2200,6 +2321,10 @@ packages: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} @@ -3479,6 +3604,15 @@ snapshots: '@types/prop-types@15.7.14': {} + '@types/quill@1.3.10': + dependencies: + parchment: 1.1.4 + + '@types/quill@2.0.14': + dependencies: + parchment: 1.1.4 + quill-delta: 5.1.0 + '@types/react-dom@18.3.2': dependencies: '@types/react': 18.3.14 @@ -3760,6 +3894,11 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + call-bind@1.0.8: dependencies: call-bind-apply-helpers: 1.0.0 @@ -3767,6 +3906,11 @@ snapshots: get-intrinsic: 1.2.5 set-function-length: 1.2.2 + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.6 + callsites@3.1.0: {} camelcase@6.3.0: {} @@ -3805,6 +3949,8 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone@2.1.2: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -3856,6 +4002,15 @@ snapshots: deep-eql@5.0.2: {} + deep-equal@1.1.2: + dependencies: + is-arguments: 1.1.1 + is-date-object: 1.1.0 + is-regex: 1.2.1 + object-is: 1.1.6 + object-keys: 1.1.1 + regexp.prototype.flags: 1.5.3 + deep-is@0.1.4: {} define-data-property@1.1.4: @@ -3866,6 +4021,12 @@ snapshots: define-lazy-prop@2.0.0: {} + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -3905,6 +4066,10 @@ snapshots: es-module-lexer@1.5.4: {} + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + esbuild-register@3.6.0(esbuild@0.24.0): dependencies: debug: 4.3.7 @@ -4061,10 +4226,20 @@ snapshots: esutils@2.0.3: {} + eventemitter3@2.0.3: {} + + eventemitter3@5.0.1: {} + expect-type@1.1.0: {} + extend@3.0.2: {} + fast-deep-equal@3.1.3: {} + fast-diff@1.1.2: {} + + fast-diff@1.3.0: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4120,6 +4295,8 @@ snapshots: function-bind@1.1.2: {} + functions-have-names@1.2.3: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -4135,6 +4312,19 @@ snapshots: has-symbols: 1.1.0 hasown: 2.0.2 + get-intrinsic@1.2.6: + dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -4210,6 +4400,11 @@ snapshots: dependencies: hasown: 2.0.2 + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-docker@2.2.1: {} is-extglob@2.1.1: {} @@ -4228,6 +4423,13 @@ snapshots: is-number@7.0.0: {} + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.16 @@ -4281,6 +4483,12 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: {} + + lodash.clonedeep@4.5.0: {} + + lodash.isequal@4.5.0: {} + lodash.merge@4.6.2: {} lodash@4.17.21: {} @@ -4311,6 +4519,8 @@ snapshots: map-or-similar@1.5.0: {} + math-intrinsics@1.1.0: {} + memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 @@ -4380,6 +4590,13 @@ snapshots: node-releases@2.0.18: {} + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -4405,6 +4622,10 @@ snapshots: dependencies: p-limit: 3.1.0 + parchment@1.1.4: {} + + parchment@3.0.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -4478,6 +4699,34 @@ snapshots: queue-microtask@1.2.3: {} + quill-delta@3.6.3: + dependencies: + deep-equal: 1.1.2 + extend: 3.0.2 + fast-diff: 1.1.2 + + quill-delta@5.1.0: + dependencies: + fast-diff: 1.3.0 + lodash.clonedeep: 4.5.0 + lodash.isequal: 4.5.0 + + quill@1.3.7: + dependencies: + clone: 2.1.2 + deep-equal: 1.1.2 + eventemitter3: 2.0.3 + extend: 3.0.2 + parchment: 1.1.4 + quill-delta: 3.6.3 + + quill@2.0.3: + dependencies: + eventemitter3: 5.0.1 + lodash-es: 4.17.21 + parchment: 3.0.0 + quill-delta: 5.1.0 + react-confetti@6.1.0(react@18.3.1): dependencies: react: 18.3.1 @@ -4516,6 +4765,14 @@ snapshots: react-is@17.0.2: {} + react-quill@2.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@types/quill': 1.3.10 + lodash: 4.17.21 + quill: 1.3.7 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-redux@9.1.2(@types/react@18.3.14)(react@18.3.1)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.3 @@ -4572,6 +4829,13 @@ snapshots: regenerator-runtime@0.14.1: {} + regexp.prototype.flags@1.5.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + require-directory@2.1.1: {} requires-port@1.0.0: {} @@ -4635,6 +4899,13 @@ snapshots: gopd: 1.2.0 has-property-descriptors: 1.0.2 + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + shallowequal@1.1.0: {} shebang-command@2.0.0: diff --git a/src/apis/board.api.ts b/src/apis/board.api.ts new file mode 100644 index 0000000..b85ad66 --- /dev/null +++ b/src/apis/board.api.ts @@ -0,0 +1,16 @@ +import { httpClient } from './http.api'; + +export const fetchUpdateReview = async ( + title: string, + tags: string[], + content: string +) => { + { + const response = await httpClient.post('/api/posts', { + title, + tags, + content, + }); + return response.data; + } +}; diff --git a/src/components/ui/atoms/Button.ts b/src/components/ui/atoms/Button.ts index 2b7dd6d..e139193 100644 --- a/src/components/ui/atoms/Button.ts +++ b/src/components/ui/atoms/Button.ts @@ -1,7 +1,7 @@ import styled from 'styled-components'; interface ButtonProps { - variant?: 'primary' | 'outline'; + variant?: 'primary' | 'outline' | 'tag'; disabled?: boolean; } @@ -18,11 +18,16 @@ const styles = { primary: ` background-color: mediumseagreen; color: white; - border: none; - - &:hover { - background-color: seagreen; - } + border: black; + height: 30px; + padding: 5px; + `, + tag: ` + background-color: white; + border: 1px solid mediumseagreen; + height: 30px; + padding: 5px; + color: mediumseagreen; `, outline: ` background-color: white; @@ -47,6 +52,7 @@ const Button = styled.button` styles.base, variant === 'primary' && styles.primary, variant === 'outline' && styles.outline, + variant === 'tag' && styles.tag, disabled && styles.disabled )} `; diff --git a/src/components/ui/molecules/QuillEditor.tsx b/src/components/ui/molecules/QuillEditor.tsx new file mode 100644 index 0000000..1ed47b6 --- /dev/null +++ b/src/components/ui/molecules/QuillEditor.tsx @@ -0,0 +1,45 @@ +import React, { useRef } from 'react'; +import ReactQuill, { Quill } from 'react-quill'; +import 'react-quill/dist/quill.snow.css'; + +interface RichTextEditorProps { + value: string; + onChange: (value: string) => void; +} + +const RichTextEditor: React.FC = ({ value, onChange }) => { + const quillRef = useRef(null); // React ref 사용 + + const modules = { + toolbar: [ + [{ header: [1, 2, false] }], + ['bold', 'italic', 'underline', 'strike'], + [{ list: 'ordered' }, { list: 'bullet' }], + ['code-block'], + ], + }; + + const formats = [ + 'header', + 'bold', + 'italic', + 'underline', + 'strike', + 'list', + 'bullet', + 'code-block', + ]; + + return ( + + ); +}; + +export default RichTextEditor; diff --git a/src/constants/TagItems.ts b/src/constants/TagItems.ts new file mode 100644 index 0000000..dd2fb9c --- /dev/null +++ b/src/constants/TagItems.ts @@ -0,0 +1,10 @@ +export const TagItems = [ + 'Javascript', + 'NodeJs', + 'HTML', + 'CSS', + 'React', + 'C', + 'JAVA', + 'Python', +]; diff --git a/src/pages/BoardWritePage.tsx b/src/pages/BoardWritePage.tsx new file mode 100644 index 0000000..2a89a7b --- /dev/null +++ b/src/pages/BoardWritePage.tsx @@ -0,0 +1,134 @@ +import { fetchUpdateReview } from '@/apis/board.api'; +import Button from '@/components/ui/atoms/Button'; +import RichTextEditor from '@/components/ui/molecules/QuillEditor'; +import { TagItems } from '@/constants/tagItems'; +import { useState } from 'react'; +import styled from 'styled-components'; + +const BoardWritePage = () => { + const [title, setTitle] = useState(''); + const [selectedTags, setSelectedTags] = useState([]); + const [content, setContent] = useState(''); + + const handleTagSelected = (index: number) => { + setSelectedTags((prev) => + prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index] + ); + }; + + const registerBoard = async () => { + if (!title.trim()) { + alert('제목을 입력해주세요.'); + return; + } + if (selectedTags.length === 0) { + alert('태그를 선택해주세요.'); + return; + } + if (!content.trim()) { + alert('내용을 입력해주세요.'); + return; + } + const selectedTagNames = selectedTags.map((index) => TagItems[index]); + try { + console.log('title: ', title); + const response = await fetchUpdateReview( + title, + selectedTagNames, + content + ); + console.log('게시글 등록 성공:', response); + alert('게시글이 성공적으로 등록되었습니다!'); + } catch (error) { + console.error('게시글 등록 실패:', error); + alert('게시글 등록에 실패했습니다. 다시 시도해주세요.'); + } + }; + + return ( + + + setTitle(e.target.value)} + /> + + + 태그를 등록해주세요 + + {TagItems.map((item, index) => ( + + ))} + + +
+ +
+ + + + +
+ ); +}; + +export default BoardWritePage; + +const WriteContainer = styled.div` + width: 100%; + height: fit-content; + border: 2px solid gray; + border-radius: 10px; + padding: 0px 0px 10px 0px; +`; + +const TitleSection = styled.div` + width: 100%; + display: flex; + align-items: center; + padding: 10px 10px 10px 20px; +`; + +const TitleInput = styled.input` + font-size: 22px; + height: 44px; + width: 500px; + border: none; + padding: 5px; +`; + +const TagSection = styled.div` + width: 100%; + height: 70px; + display: flex; + flex-direction: column; + padding: 10px 10px 10px 20px; + gap: 5px; +`; + +const TagTitle = styled.div` + font-size: 18px; + padding-left: 5px; +`; + +const TagWrapper = styled.div` + display: flex; + gap: 10px; + padding-left: 5px; +`; + +const RegisterSection = styled.div` + display: flex; + flex-direction: row-reverse; + padding: 0px 20px 0px 20px; + gap: 10px; +`; diff --git a/src/routes/router.tsx b/src/routes/router.tsx index 3718e99..8c37bd5 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -8,6 +8,7 @@ import JoinPage from '@/pages/JoinPage'; import LoginPage from '@/pages/LoginPage'; import MyPage from '@/pages/MyPage'; import ProtectedRoute from '@/admin/AdminRoute'; +import BoardWritePage from '@/pages/BoardWritePage'; const router = [ { @@ -18,6 +19,10 @@ const router = [ path: '/', element: , }, + { + path: '/boardwrite', + element: , + }, { path: '/mypage', element: , diff --git a/src/styles/reset.css b/src/styles/reset.css index d971da6..6c9d5d7 100644 --- a/src/styles/reset.css +++ b/src/styles/reset.css @@ -2,6 +2,7 @@ v2.0 | 20110126 License: none (public domain) */ +@import 'react-quill/dist/quill.snow.css'; html, body,