From 12865a12f27d65150095322b239376ea6fb76086 Mon Sep 17 00:00:00 2001 From: HAM!DREZA Date: Mon, 20 Jan 2025 15:36:50 +0330 Subject: [PATCH 1/3] create discount and ads section --- package-lock.json | 237 ++++++++++++++++++ package.json | 2 + src/App.tsx | 1 - src/components/Editor.jsx | 55 ++++ src/config/Pages.ts | 3 + src/langs/fa.json | 76 ++++++ src/pages/ads/AdsList.tsx | 135 ++++++++++ src/pages/ads/CreateAds.tsx | 108 ++++++++ src/pages/ads/components/ImageUploader.tsx | 49 ++++ src/pages/blog/BlogList.tsx | 147 +++++++++++ src/pages/blog/CreateBlog.tsx | 122 +++++++++ src/pages/blog/components/ImageUploader.tsx | 49 ++++ src/pages/discounts/CreateDiscount.tsx | 190 ++++++++++++++ src/pages/discounts/DiscountsList.tsx | 116 +++++++++ .../discounts/components/ImageUploader.tsx | 49 ++++ src/router/Main.tsx | 12 + 16 files changed, 1350 insertions(+), 1 deletion(-) create mode 100644 src/components/Editor.jsx create mode 100644 src/pages/ads/AdsList.tsx create mode 100644 src/pages/ads/CreateAds.tsx create mode 100644 src/pages/ads/components/ImageUploader.tsx create mode 100644 src/pages/blog/BlogList.tsx create mode 100644 src/pages/blog/CreateBlog.tsx create mode 100644 src/pages/blog/components/ImageUploader.tsx create mode 100644 src/pages/discounts/CreateDiscount.tsx create mode 100644 src/pages/discounts/DiscountsList.tsx create mode 100644 src/pages/discounts/components/ImageUploader.tsx diff --git a/package-lock.json b/package-lock.json index cd0f660..a1539b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,11 @@ "@headlessui/react": "^2.2.0", "@material-tailwind/react": "^2.1.10", "@tanstack/react-query": "^5.62.8", + "draft-js": "^0.11.7", "formik": "^2.4.6", "i18next": "^24.2.0", "iconsax-react": "^0.0.8", + "quill": "^2.0.3", "rc-rate": "^2.13.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -1839,6 +1841,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "22.10.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", + "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~6.20.0" + } + }, "node_modules/@types/prop-types": { "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", @@ -2227,6 +2241,12 @@ "node": ">=10" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, "node_modules/attr-accept": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", @@ -2515,6 +2535,26 @@ "node": ">=18" } }, + "node_modules/core-js": { + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", + "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2597,6 +2637,21 @@ "dev": true, "license": "MIT" }, + "node_modules/draft-js": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz", + "integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==", + "license": "MIT", + "dependencies": { + "fbjs": "^2.0.0", + "immutable": "~3.7.4", + "object-assign": "^4.1.1" + }, + "peerDependencies": { + "react": ">=0.14.0", + "react-dom": ">=0.14.0" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2858,6 +2913,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2865,6 +2926,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -2919,6 +2986,28 @@ "reusify": "^1.0.4" } }, + "node_modules/fbjs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", + "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", + "license": "MIT", + "dependencies": { + "core-js": "^3.6.4", + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -3296,6 +3385,15 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3566,6 +3664,18 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "license": "MIT" }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3693,6 +3803,26 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -3796,6 +3926,12 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parchment": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", + "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==", + "license": "BSD-3-Clause" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4072,6 +4208,15 @@ "node": ">= 0.8.0" } }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4120,6 +4265,35 @@ ], "license": "MIT" }, + "node_modules/quill": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", + "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", + "license": "BSD-3-Clause", + "dependencies": { + "eventemitter3": "^5.0.1", + "lodash-es": "^4.17.21", + "parchment": "^3.0.0", + "quill-delta": "^5.1.0" + }, + "engines": { + "npm": ">=8.2.3" + } + }, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "license": "MIT", + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/rc-rate": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", @@ -4499,6 +4673,12 @@ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", "license": "MIT" }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4848,6 +5028,12 @@ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", "license": "MIT" }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", @@ -4942,6 +5128,41 @@ "typescript": ">=4.8.4 <5.8.0" } }, + "node_modules/ua-parser-js": { + "version": "0.7.40", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.40.tgz", + "integrity": "sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -5071,6 +5292,22 @@ "node": ">=0.10.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 18cf539..fd291aa 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ "@headlessui/react": "^2.2.0", "@material-tailwind/react": "^2.1.10", "@tanstack/react-query": "^5.62.8", + "draft-js": "^0.11.7", "formik": "^2.4.6", "i18next": "^24.2.0", "iconsax-react": "^0.0.8", + "quill": "^2.0.3", "rc-rate": "^2.13.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/src/App.tsx b/src/App.tsx index 2d8c835..3745f8e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,7 +11,6 @@ import { IApiErrorRepsonse } from './types/error.types' import MainRouter from './router/Main' import AuthRouter from './router/Auth' import { Pages } from './config/Pages' - i18next.init({ interpolation: { escapeValue: false }, lng: 'fa', diff --git a/src/components/Editor.jsx b/src/components/Editor.jsx new file mode 100644 index 0000000..a69b9ed --- /dev/null +++ b/src/components/Editor.jsx @@ -0,0 +1,55 @@ +import { forwardRef, useEffect, useLayoutEffect, useRef } from 'react'; + +// Editor is an uncontrolled React component +const Editor = forwardRef( + ({ readOnly, defaultValue, onTextChange, onSelectionChange }, ref) => { + const containerRef = useRef(null); + const defaultValueRef = useRef(defaultValue); + const onTextChangeRef = useRef(onTextChange); + const onSelectionChangeRef = useRef(onSelectionChange); + + useLayoutEffect(() => { + onTextChangeRef.current = onTextChange; + onSelectionChangeRef.current = onSelectionChange; + }); + + useEffect(() => { + ref.current?.enable(!readOnly); + }, [ref, readOnly]); + + useEffect(() => { + const container = containerRef.current; + const editorContainer = container.appendChild( + container.ownerDocument.createElement('div'), + ); + const quill = new Quill(editorContainer, { + theme: 'snow', + }); + + ref.current = quill; + + if (defaultValueRef.current) { + quill.setContents(defaultValueRef.current); + } + + quill.on(Quill.events.TEXT_CHANGE, (...args) => { + onTextChangeRef.current?.(...args); + }); + + quill.on(Quill.events.SELECTION_CHANGE, (...args) => { + onSelectionChangeRef.current?.(...args); + }); + + return () => { + ref.current = null; + container.innerHTML = ''; + }; + }, [ref]); + + return
; + }, +); + +Editor.displayName = 'Editor'; + +export default Editor; \ No newline at end of file diff --git a/src/config/Pages.ts b/src/config/Pages.ts index de2c9be..94fb684 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -40,6 +40,7 @@ export const Pages = { }, discount: { list: "/discounts/list", + create: "/discounts/create" }, referralCode: { list: "/referral-code/list", @@ -49,9 +50,11 @@ export const Pages = { }, ads: { list: "/ads/list", + create: "/ads/create" }, blog: { list: "/blog/list", + create: "/blog/create" }, messages: { list: "/messages/list", diff --git a/src/langs/fa.json b/src/langs/fa.json index 3dcf200..e05154a 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -158,6 +158,82 @@ "info_ticket": "اطلاعات تیکت", "update_sms": "به روزرسانی این تیکت از طریق پیامک اطلاع داده میشود" }, + "ads": { + "ads": "تبلیغات", + "upload": "آپلود", + "deactive": "غیرفعال", + "submit": "ثبت تبلیغ", + "upload_picture": "تصویر نمایش تبلیغ", + "to_upload_message": "تصویر مورد نظر را آپلود کنید", + "new_ads": "افزودن تبلیغ", + "location": "جایگاه", + "startDate": "تاریخ شروع نمایش", + "endDate": "تاریخ پایان نمایش", + "search": "جستجو", + "number": "شماره", + "title": "عنوان", + "date": "تاریخ", + "status": "وضعیت", + "enter_your_title": "عنوان تبلیغ را وارد کنید", + "link": "لینک", + "enter_your_link": "لینک تبلیغ را وارد کنید" + }, + "discount": { + "list": "لیست تخفیفات", + "type": "نوع تخفیف", + "price": "مبلغ تخفیف", + "title": "عنوان کد", + "code": "کد تخفیف", + "enter_discount_description": "عنوان کد تخفیف را وارد کنید", + "add_new_discount": "افزودن تخفیف", + "auto_generate_code": "ساخت کد", + "price_or_percent": "درصد / مبلغ تخفیف", + "enter_price_or_percent": "درصد / مبلغ تخفیف را وارد کنید", + "service": "سرویس", + "status": "وضعیت", + "number": "شماره", + "startDate": "تاریخ شروع", + "endDate": "تاریخ پایان", + "service_status": "وضعیت سرویس", + "availabe_service": "سرویس هایی که شامل تخفیف میشوند", + "new_discount": "کد تخفیف جدید", + "submit": "ثبت تخفیف", + "discount_code": "کد تخفیف", + "direct_discount": "تخفیف مستقیم", + "fixed_amount": "مبلغ ثابت", + "percent": "درصد" + }, + "blog": { + "blog": "بلاگ", + "category": "دسته بندی", + "new_blog": "افزودن بلاگ", + "blog_title": "عنوان بلاگ", + "blog_Summary": "خلاصه بلاگ", + "shareDate": "تاریخ انتشار", + "enter_your_title": "عنوان بلاگ را وارد کنید", + "add_blog": "افزودن بلاگ", + "price": "مبلغ تخفیف", + "title": "عنوان کد", + "code": "کد تخفیف", + "enter_discount_description": "عنوان کد تخفیف را وارد کنید", + "add_new_discount": "افزودن تخفیف", + "auto_generate_code": "ساخت کد", + "price_or_percent": "درصد / مبلغ تخفیف", + "enter_price_or_percent": "درصد / مبلغ تخفیف را وارد کنید", + "service": "سرویس", + "status": "وضعیت", + "number": "شماره", + "startDate": "تاریخ شروع", + "endDate": "تاریخ پایان", + "service_status": "وضعیت سرویس", + "availabe_service": "سرویس هایی که شامل تخفیف میشوند", + "new_discount": "کد تخفیف جدید", + "submit": "ثبت بلاگ", + "discount_code": "کد تخفیف", + "direct_discount": "تخفیف مستقیم", + "fixed_amount": "مبلغ ثابت", + "percent": "درصد" + }, "receip": { "receip_list": "لیست صورتحساب ها", "dont_pay": "پرداخت نشده", diff --git a/src/pages/ads/AdsList.tsx b/src/pages/ads/AdsList.tsx new file mode 100644 index 0000000..0a5c1a2 --- /dev/null +++ b/src/pages/ads/AdsList.tsx @@ -0,0 +1,135 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Button from '../../components/Button' +import { Add, Eye } from 'iconsax-react' +import Td from '../../components/Td' +import { Link } from 'react-router-dom' +import { Pages } from '../../config/Pages' +import SwitchComponent from '../../components/Switch' +import DatePickerComponent from '../../components/DatePicker' +import Select from '../../components/Select' +import Input from '../../components/Input' +const TicketList: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('ads.ads')} +
+ + + + +
+ + + + +
+
+
+
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+ +
+ +
+
+ + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + { }} + /> + + + + +
+ + + + + + { }} + /> + + + + +
+
+
+ ) +} + +export default TicketList \ No newline at end of file diff --git a/src/pages/ads/CreateAds.tsx b/src/pages/ads/CreateAds.tsx new file mode 100644 index 0000000..cc3a9f2 --- /dev/null +++ b/src/pages/ads/CreateAds.tsx @@ -0,0 +1,108 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Input from '../../components/Input' +import Button from '../../components/Button' +import SwitchComponent from '../../components/Switch' +import { TickCircle, TickSquare, Link2 } from 'iconsax-react' +import DatePickerComponent from '../../components/DatePicker' +import ImageUploader from './components/ImageUploader' +const CreateTicket: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('ads.new_ads')} +
+ +
+
+
+
+ +
+
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> + { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+ + +
+
+
+
+

+ وضعیت تبلیغ +

+
+
+ {t('ads.deactive')} +
+ { }} + /> +
+
+

{t('ads.location')}

+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+ +
+
+ +
+ ) +} + +export default CreateTicket \ No newline at end of file diff --git a/src/pages/ads/components/ImageUploader.tsx b/src/pages/ads/components/ImageUploader.tsx new file mode 100644 index 0000000..966c176 --- /dev/null +++ b/src/pages/ads/components/ImageUploader.tsx @@ -0,0 +1,49 @@ + +import { FC, useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Image, DocumentUpload } from 'iconsax-react' +import { useDropzone } from 'react-dropzone' + + + +const ImageUploader: FC = () => { + const { t } = useTranslation('global') + const [file, setFile] = useState() + const onDrop = useCallback((acceptedFiles: File[]) => { + setFile(acceptedFiles[0]) + }, []) + const { getRootProps, getInputProps } = useDropzone({ onDrop }) + + return( + <> +

{t('ads.upload_picture')}

+
+
+ +

+ { + file ? + file.name + : + t('ads.to_upload_message') + + } +

+
+ + +
+
+
+ + ) +} +export default ImageUploader \ No newline at end of file diff --git a/src/pages/blog/BlogList.tsx b/src/pages/blog/BlogList.tsx new file mode 100644 index 0000000..0b43912 --- /dev/null +++ b/src/pages/blog/BlogList.tsx @@ -0,0 +1,147 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Button from '../../components/Button' +import { Add, Eye } from 'iconsax-react' +import Td from '../../components/Td' +import { Link } from 'react-router-dom' +import { Pages } from '../../config/Pages' +import SwitchComponent from '../../components/Switch' +import DatePickerComponent from '../../components/DatePicker' +import Select from '../../components/Select' +import Input from '../../components/Input' +const BlogList: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('blog.blog')} +
+ + + + +
+ + + + +
+
+
+
+ +
+
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+ + +
+ +
+ +
+
+ + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + { }} + /> + + + + +
+ + + + + + { }} + /> + + + + +
+
+
+ ) +} + +export default BlogList \ No newline at end of file diff --git a/src/pages/blog/CreateBlog.tsx b/src/pages/blog/CreateBlog.tsx new file mode 100644 index 0000000..7e2055a --- /dev/null +++ b/src/pages/blog/CreateBlog.tsx @@ -0,0 +1,122 @@ + +import { FC, useEffect } from 'react' +import { useTranslation } from 'react-i18next' +import Input from '../../components/Input' +import Button from '../../components/Button' +import SwitchComponent from '../../components/Switch' +import { TickCircle, TickSquare, Link2 } from 'iconsax-react' +import DatePickerComponent from '../../components/DatePicker' +import ImageUploader from './components/ImageUploader' +import "quill/dist/quill.snow.css"; +import Quill from 'quill'; +const CreateTicket: FC = () => { + const { t } = useTranslation('global') + useEffect(() => { + const quill = new Quill('#editor', { + theme: 'snow', + }); + }, []); + return ( +
+
+
+ {t('blog.add_blog')} +
+ +
+
+
+
+ +
+ +
+
+
+ + +
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> + { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+ + +
+
+
+
+

+ وضعیت تبلیغ +

+
+
+ {t('ads.deactive')} +
+ { }} + /> +
+
+

{t('ads.location')}

+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+ +
+
+ +
+ ) +} + +export default CreateTicket \ No newline at end of file diff --git a/src/pages/blog/components/ImageUploader.tsx b/src/pages/blog/components/ImageUploader.tsx new file mode 100644 index 0000000..966c176 --- /dev/null +++ b/src/pages/blog/components/ImageUploader.tsx @@ -0,0 +1,49 @@ + +import { FC, useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Image, DocumentUpload } from 'iconsax-react' +import { useDropzone } from 'react-dropzone' + + + +const ImageUploader: FC = () => { + const { t } = useTranslation('global') + const [file, setFile] = useState() + const onDrop = useCallback((acceptedFiles: File[]) => { + setFile(acceptedFiles[0]) + }, []) + const { getRootProps, getInputProps } = useDropzone({ onDrop }) + + return( + <> +

{t('ads.upload_picture')}

+
+
+ +

+ { + file ? + file.name + : + t('ads.to_upload_message') + + } +

+
+ + +
+
+
+ + ) +} +export default ImageUploader \ No newline at end of file diff --git a/src/pages/discounts/CreateDiscount.tsx b/src/pages/discounts/CreateDiscount.tsx new file mode 100644 index 0000000..1109600 --- /dev/null +++ b/src/pages/discounts/CreateDiscount.tsx @@ -0,0 +1,190 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Input from '../../components/Input' +import Button from '../../components/Button' +import SwitchComponent from '../../components/Switch' +import { TickCircle, TickSquare, Refresh } from 'iconsax-react' +import DatePickerComponent from '../../components/DatePicker' +import ImageUploader from './components/ImageUploader' +import RadioGroup from '../../components/RadioGroup' +const CreateTicket: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('discount.new_discount')} +
+ +
+
+
+
+ {t('discount.type')} +
+ +
+
+ + +
+ + +
+ +
+ +
+ + + + + +
+ + +
+ + {t('discount.price')} +
+ +
+ +
+ + + + +
+ + + + + + + + + + +
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> + { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+
+
+

+ {t('discount.service_status')} +

+
+
+ {t('ads.deactive')} +
+ { }} + /> +
+
+

{t('discount.availabe_service')}

+
+ + + + + +
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+ +
+
+ +
+ ) +} + +export default CreateTicket \ No newline at end of file diff --git a/src/pages/discounts/DiscountsList.tsx b/src/pages/discounts/DiscountsList.tsx new file mode 100644 index 0000000..7e660dc --- /dev/null +++ b/src/pages/discounts/DiscountsList.tsx @@ -0,0 +1,116 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Button from '../../components/Button' +import { Add, Eye } from 'iconsax-react' +import Td from '../../components/Td' +import { Link } from 'react-router-dom' +import { Pages } from '../../config/Pages' +import SwitchComponent from '../../components/Switch' +import Input from '../../components/Input' +const TicketList: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('discount.list')} +
+ + + + +
+ + + + +
+
+ +
+ +
+ +
+
+ + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + { }} + /> + + + + +
+ + + + + + + + { }} + /> + + + + +
+
+
+ ) +} + +export default TicketList \ No newline at end of file diff --git a/src/pages/discounts/components/ImageUploader.tsx b/src/pages/discounts/components/ImageUploader.tsx new file mode 100644 index 0000000..966c176 --- /dev/null +++ b/src/pages/discounts/components/ImageUploader.tsx @@ -0,0 +1,49 @@ + +import { FC, useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Image, DocumentUpload } from 'iconsax-react' +import { useDropzone } from 'react-dropzone' + + + +const ImageUploader: FC = () => { + const { t } = useTranslation('global') + const [file, setFile] = useState() + const onDrop = useCallback((acceptedFiles: File[]) => { + setFile(acceptedFiles[0]) + }, []) + const { getRootProps, getInputProps } = useDropzone({ onDrop }) + + return( + <> +

{t('ads.upload_picture')}

+
+
+ +

+ { + file ? + file.name + : + t('ads.to_upload_message') + + } +

+
+ + +
+
+
+ + ) +} +export default ImageUploader \ No newline at end of file diff --git a/src/router/Main.tsx b/src/router/Main.tsx index 2685135..3553c33 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -5,6 +5,12 @@ import { Route, Routes } from 'react-router-dom' import { Pages } from '../config/Pages' import Home from '../pages/home/Home' import MyServices from '../pages/service/MyServices' +import DiscountsList from '../pages/discounts/DiscountsList' +import CreateDiscount from '../pages/discounts/CreateDiscount' +import AdsList from '../pages/ads/AdsList' +import BlogList from '../pages/blog/BlogList' +import CreateBlog from '../pages/blog/CreateBlog' +import CreateAds from '../pages/ads/CreateAds' import TicketList from '../pages/ticket/TicketList' import CreateTicket from '../pages/ticket/CreateTicket' import TicketDetail from '../pages/ticket/Detail' @@ -38,6 +44,12 @@ const MainRouter: FC = () => { } /> } /> } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> } /> } /> From 59eeedff1ff2facc1e3f9f032a9e508fcd9ddfa7 Mon Sep 17 00:00:00 2001 From: HAM!DREZA Date: Tue, 21 Jan 2025 14:47:59 +0330 Subject: [PATCH 2/3] add ckEditor --- src/components/Editor.jsx | 85 ++++++++------------- src/config/Pages.ts | 3 +- src/index.css | 4 + src/langs/fa.json | 5 ++ src/pages/blog/CreateBlog.tsx | 58 +++++++------- src/pages/blog/components/ImageUploader.tsx | 2 +- 6 files changed, 71 insertions(+), 86 deletions(-) diff --git a/src/components/Editor.jsx b/src/components/Editor.jsx index a69b9ed..de66f88 100644 --- a/src/components/Editor.jsx +++ b/src/components/Editor.jsx @@ -1,55 +1,30 @@ -import { forwardRef, useEffect, useLayoutEffect, useRef } from 'react'; - -// Editor is an uncontrolled React component -const Editor = forwardRef( - ({ readOnly, defaultValue, onTextChange, onSelectionChange }, ref) => { - const containerRef = useRef(null); - const defaultValueRef = useRef(defaultValue); - const onTextChangeRef = useRef(onTextChange); - const onSelectionChangeRef = useRef(onSelectionChange); - - useLayoutEffect(() => { - onTextChangeRef.current = onTextChange; - onSelectionChangeRef.current = onSelectionChange; - }); - - useEffect(() => { - ref.current?.enable(!readOnly); - }, [ref, readOnly]); - - useEffect(() => { - const container = containerRef.current; - const editorContainer = container.appendChild( - container.ownerDocument.createElement('div'), - ); - const quill = new Quill(editorContainer, { - theme: 'snow', - }); - - ref.current = quill; - - if (defaultValueRef.current) { - quill.setContents(defaultValueRef.current); - } - - quill.on(Quill.events.TEXT_CHANGE, (...args) => { - onTextChangeRef.current?.(...args); - }); - - quill.on(Quill.events.SELECTION_CHANGE, (...args) => { - onSelectionChangeRef.current?.(...args); - }); - - return () => { - ref.current = null; - container.innerHTML = ''; - }; - }, [ref]); - - return
; - }, -); - -Editor.displayName = 'Editor'; - -export default Editor; \ No newline at end of file +import React from 'react'; +import ReactDOM from 'react-dom'; +import {Editor, EditorState} from 'draft-js'; + +function MyEditor() { + const [editorState, setEditorState] = React.useState( + EditorState.createEmpty() + ); + + const editor = React.useRef(null); + + function focusEditor() { + editor.current.focus(); + } + + React.useEffect(() => { + focusEditor() + }, []); + + return ( +
+ setEditorState(editorState)} + /> +
+ ); +} +export default MyEditor \ No newline at end of file diff --git a/src/config/Pages.ts b/src/config/Pages.ts index 94fb684..face8e3 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -54,7 +54,8 @@ export const Pages = { }, blog: { list: "/blog/list", - create: "/blog/create" + create: "/blog/create", + category: "/blog/category" }, messages: { list: "/messages/list", diff --git a/src/index.css b/src/index.css index dc00132..bb8f998 100644 --- a/src/index.css +++ b/src/index.css @@ -126,3 +126,7 @@ tbody tr { .overflowX::-webkit-scrollbar { display: none; } + +.ql-toolbar:first-child{ + display: none !important; +} \ No newline at end of file diff --git a/src/langs/fa.json b/src/langs/fa.json index e05154a..ecf3347 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -209,6 +209,11 @@ "new_blog": "افزودن بلاگ", "blog_title": "عنوان بلاگ", "blog_Summary": "خلاصه بلاگ", + "content": "محتوا", + "blog_status": "وضعیت بلاگ", + "featured_image": "تصویر شاخص", + "tags": "برچسب ها", + "tag_hint": "جدا کردن با کاما یا کلید Enter ", "shareDate": "تاریخ انتشار", "enter_your_title": "عنوان بلاگ را وارد کنید", "add_blog": "افزودن بلاگ", diff --git a/src/pages/blog/CreateBlog.tsx b/src/pages/blog/CreateBlog.tsx index 7e2055a..e440670 100644 --- a/src/pages/blog/CreateBlog.tsx +++ b/src/pages/blog/CreateBlog.tsx @@ -9,12 +9,15 @@ import DatePickerComponent from '../../components/DatePicker' import ImageUploader from './components/ImageUploader' import "quill/dist/quill.snow.css"; import Quill from 'quill'; -const CreateTicket: FC = () => { +const CreateBlog: FC = () => { const { t } = useTranslation('global') useEffect(() => { const quill = new Quill('#editor', { theme: 'snow', - }); + }); + const quill2 = new Quill('#editor2', { + theme: 'snow', + }); }, []); return (
@@ -42,37 +45,23 @@ const CreateTicket: FC = () => { />
-
-
-
- - -
- { }} - placeholder='' - defaulValue='1400-01-01' - /> - { }} - placeholder='' - defaulValue='1400-01-01' - /> +

{t('blog.blog_Summary')}

+
+
-
- - + +

{t('blog.content')}

+
+
+
+ +

- وضعیت تبلیغ + {t('blog.blog_status')}

@@ -84,7 +73,7 @@ const CreateTicket: FC = () => { />
-

{t('ads.location')}

+

{t('blog.category')}

@@ -112,6 +101,17 @@ const CreateTicket: FC = () => {
+

{t('blog.tags')}

+
+ +

+ {t('blog.tag_hint')} +

+
+ + + +
@@ -119,4 +119,4 @@ const CreateTicket: FC = () => { ) } -export default CreateTicket \ No newline at end of file +export default CreateBlog \ No newline at end of file diff --git a/src/pages/blog/components/ImageUploader.tsx b/src/pages/blog/components/ImageUploader.tsx index 966c176..998ac91 100644 --- a/src/pages/blog/components/ImageUploader.tsx +++ b/src/pages/blog/components/ImageUploader.tsx @@ -16,7 +16,7 @@ const ImageUploader: FC = () => { return( <> -

{t('ads.upload_picture')}

+

{t('blog.featured_image')}

From fbf6a768bfc107d8349fe5b24ea893eb931ef3de Mon Sep 17 00:00:00 2001 From: HAM!DREZA Date: Tue, 21 Jan 2025 16:36:43 +0330 Subject: [PATCH 3/3] fix warnings from components --- src/langs/fa.json | 5 + src/pages/ads/AdsList.tsx | 16 +-- src/pages/ads/CreateAds.tsx | 8 +- src/pages/ads/components/ImageUploader.tsx | 72 +++++----- src/pages/blog/BlogCategory.tsx | 147 +++++++++++++++++++++ src/pages/blog/BlogList.tsx | 12 +- src/pages/blog/CreateBlog.tsx | 18 +-- src/pages/discounts/CreateDiscount.tsx | 46 +------ src/pages/discounts/DiscountsList.tsx | 4 +- src/router/Main.tsx | 2 + 10 files changed, 219 insertions(+), 111 deletions(-) create mode 100644 src/pages/blog/BlogCategory.tsx diff --git a/src/langs/fa.json b/src/langs/fa.json index 18b0684..a0f4823 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -220,6 +220,11 @@ "shareDate": "تاریخ انتشار", "enter_your_title": "عنوان بلاگ را وارد کنید", "add_blog": "افزودن بلاگ", +"blog_category": "دسته بندی بلاگ", +"add_category": "اضافه کردن دسته بندی", +"category_status": "وضعیت دسته بندی", +"category_title": "عنوان دسته بندی", +"parent_category": "دسته بندی مادر", "price": "مبلغ تخفیف", "title": "عنوان کد", "code": "کد تخفیف", diff --git a/src/pages/ads/AdsList.tsx b/src/pages/ads/AdsList.tsx index 0a5c1a2..b7a34ba 100644 --- a/src/pages/ads/AdsList.tsx +++ b/src/pages/ads/AdsList.tsx @@ -9,7 +9,7 @@ import SwitchComponent from '../../components/Switch' import DatePickerComponent from '../../components/DatePicker' import Select from '../../components/Select' import Input from '../../components/Input' -const TicketList: FC = () => { +const AddList: FC = () => { const { t } = useTranslation('global') return (
@@ -31,12 +31,8 @@ const TicketList: FC = () => {
- - - -
-
+
{
- -
+
{
- - -
@@ -132,4 +124,4 @@ const TicketList: FC = () => { ) } -export default TicketList \ No newline at end of file +export default AddList \ No newline at end of file diff --git a/src/pages/ads/CreateAds.tsx b/src/pages/ads/CreateAds.tsx index cc3a9f2..bc5b980 100644 --- a/src/pages/ads/CreateAds.tsx +++ b/src/pages/ads/CreateAds.tsx @@ -6,7 +6,7 @@ import SwitchComponent from '../../components/Switch' import { TickCircle, TickSquare, Link2 } from 'iconsax-react' import DatePickerComponent from '../../components/DatePicker' import ImageUploader from './components/ImageUploader' -const CreateTicket: FC = () => { +const CreateAd: FC = () => { const { t } = useTranslation('global') return (
@@ -25,7 +25,7 @@ const CreateTicket: FC = () => {
-
+
{
-
+

وضعیت تبلیغ @@ -105,4 +105,4 @@ const CreateTicket: FC = () => { ) } -export default CreateTicket \ No newline at end of file +export default CreateAd \ No newline at end of file diff --git a/src/pages/ads/components/ImageUploader.tsx b/src/pages/ads/components/ImageUploader.tsx index 966c176..ad623e9 100644 --- a/src/pages/ads/components/ImageUploader.tsx +++ b/src/pages/ads/components/ImageUploader.tsx @@ -7,43 +7,43 @@ import { useDropzone } from 'react-dropzone' const ImageUploader: FC = () => { - const { t } = useTranslation('global') - const [file, setFile] = useState() - const onDrop = useCallback((acceptedFiles: File[]) => { - setFile(acceptedFiles[0]) - }, []) - const { getRootProps, getInputProps } = useDropzone({ onDrop }) - - return( - <> -

{t('ads.upload_picture')}

-
-
- -

- { - file ? - file.name - : - t('ads.to_upload_message') + const { t } = useTranslation('global') + const [file, setFile] = useState() + const onDrop = useCallback((acceptedFiles: File[]) => { + setFile(acceptedFiles[0]) + }, []) + const { getRootProps, getInputProps } = useDropzone({ onDrop }) - } -

-
- - + return ( + <> +

{t('ads.upload_picture')}

+
+
+ +

+ { + file ? + file.name + : + t('ads.to_upload_message') + + } +

+
+ + +
+
-
-
- - ) + + ) } export default ImageUploader \ No newline at end of file diff --git a/src/pages/blog/BlogCategory.tsx b/src/pages/blog/BlogCategory.tsx new file mode 100644 index 0000000..5229686 --- /dev/null +++ b/src/pages/blog/BlogCategory.tsx @@ -0,0 +1,147 @@ + +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Select from '../../components/Select' +import Input from '../../components/Input' +import Td from '../../components/Td' +import SwitchComponent from '../../components/Switch' +import { TickSquare, More, TickCircle } from 'iconsax-react' +import "quill/dist/quill.snow.css"; +import Button from '../../components/Button' +const BlogCategory: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('blog.blog_category')} +
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ +
+
+ + + + + + { }} + /> + + +
+
+ +
+
+ + + + + + { }} + /> + + +
+
+
+
+
+

{t('blog.add_category')}

+
+

+ {t('blog.category_status')} +

+
+
+ {t('ads.deactive')} +
+ { }} + /> +
+
+

{t('blog.category_title')}

+
+ +
+

{t('blog.parent_category')}

+
+ +
+ + +
+
+
+ ) +} +export default BlogCategory \ No newline at end of file diff --git a/src/pages/blog/BlogList.tsx b/src/pages/blog/BlogList.tsx index 0b43912..60e46c1 100644 --- a/src/pages/blog/BlogList.tsx +++ b/src/pages/blog/BlogList.tsx @@ -36,9 +36,9 @@ const BlogList: FC = () => {
-
-
-
+
+
+
{ className='bg-white border' />
-
+
{ }} @@ -73,7 +73,7 @@ const BlogList: FC = () => {
-
+
{ const { t } = useTranslation('global') useEffect(() => { - const quill = new Quill('#editor', { + new Quill('#editor', { theme: 'snow', }); - const quill2 = new Quill('#editor2', { + new Quill('#editor2', { theme: 'snow', }); }, []); @@ -36,7 +35,7 @@ const CreateBlog: FC = () => {
-
+
{
- +
-
+

{t('blog.blog_status')} @@ -103,15 +102,12 @@ const CreateBlog: FC = () => {

{t('blog.tags')}

- +

{t('blog.tag_hint')}

- - -
diff --git a/src/pages/discounts/CreateDiscount.tsx b/src/pages/discounts/CreateDiscount.tsx index 1109600..7657150 100644 --- a/src/pages/discounts/CreateDiscount.tsx +++ b/src/pages/discounts/CreateDiscount.tsx @@ -5,9 +5,8 @@ import Button from '../../components/Button' import SwitchComponent from '../../components/Switch' import { TickCircle, TickSquare, Refresh } from 'iconsax-react' import DatePickerComponent from '../../components/DatePicker' -import ImageUploader from './components/ImageUploader' import RadioGroup from '../../components/RadioGroup' -const CreateTicket: FC = () => { +const CreateDiscount: FC = () => { const { t } = useTranslation('global') return (
@@ -42,21 +41,18 @@ const CreateTicket: FC = () => { value: 'year' } ]} - onChange={''} + onChange={() => ''} selected={''} />
- -
- -
-
-
- - - - -
- -
- {t('discount.price')}
{ value: 'year' } ]} - onChange={''} + onChange={() => ''} selected={''} />
-
- - -
- - - - - - - - - -
{

{t('discount.availabe_service')}

- - - -
@@ -179,12 +148,9 @@ const CreateTicket: FC = () => {
-
-
) } - -export default CreateTicket \ No newline at end of file +export default CreateDiscount \ No newline at end of file diff --git a/src/pages/discounts/DiscountsList.tsx b/src/pages/discounts/DiscountsList.tsx index 7e660dc..7b6ac89 100644 --- a/src/pages/discounts/DiscountsList.tsx +++ b/src/pages/discounts/DiscountsList.tsx @@ -7,7 +7,7 @@ import { Link } from 'react-router-dom' import { Pages } from '../../config/Pages' import SwitchComponent from '../../components/Switch' import Input from '../../components/Input' -const TicketList: FC = () => { +const DiscountList: FC = () => { const { t } = useTranslation('global') return (
@@ -113,4 +113,4 @@ const TicketList: FC = () => { ) } -export default TicketList \ No newline at end of file +export default DiscountList \ No newline at end of file diff --git a/src/router/Main.tsx b/src/router/Main.tsx index f387636..86d8cf0 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -10,6 +10,7 @@ import CreateDiscount from '../pages/discounts/CreateDiscount' import AdsList from '../pages/ads/AdsList' import BlogList from '../pages/blog/BlogList' import CreateBlog from '../pages/blog/CreateBlog' +import BlogCategory from '../pages/blog/BlogCategory' import CreateAds from '../pages/ads/CreateAds' import TicketList from '../pages/ticket/TicketList' import CreateTicket from '../pages/ticket/CreateTicket' @@ -61,6 +62,7 @@ const MainRouter: FC = () => { } /> } /> } /> + } /> } /> } /> } />