diff --git a/package-lock.json b/package-lock.json index dbe6129..427c4b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@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", @@ -1852,6 +1853,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", @@ -2240,6 +2253,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", @@ -2528,6 +2547,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", @@ -2610,6 +2649,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", @@ -2944,6 +2998,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", @@ -3325,7 +3401,10 @@ "version": "3.7.6", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", +<<<<<<< HEAD "dev": true, +======= +>>>>>>> add-discount-blog "license": "BSD-3-Clause", "engines": { "node": ">=0.8.0" @@ -3740,6 +3819,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", @@ -4125,6 +4224,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", @@ -4581,6 +4689,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", @@ -4930,6 +5044,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", @@ -5024,6 +5144,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", @@ -5153,6 +5308,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 8510f6e..066e8a8 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@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", diff --git a/src/App.tsx b/src/App.tsx index 950f6f2..f69517b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,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..de66f88 --- /dev/null +++ b/src/components/Editor.jsx @@ -0,0 +1,30 @@ +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 1700fb3..ac9dc15 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -45,6 +45,7 @@ export const Pages = { }, discount: { list: "/discounts/list", + create: "/discounts/create" }, referralCode: { list: "/referral-code/list", @@ -54,9 +55,12 @@ export const Pages = { }, ads: { list: "/ads/list", + create: "/ads/create" }, blog: { list: "/blog/list", + create: "/blog/create", + category: "/blog/category" }, messages: { list: "/messages/list", diff --git a/src/index.css b/src/index.css index fb404d9..e9202e9 100644 --- a/src/index.css +++ b/src/index.css @@ -142,3 +142,6 @@ tbody tr { .ql-editor { @apply !text-right; } +.ql-toolbar:first-child { + display: none !important; +} diff --git a/src/langs/fa.json b/src/langs/fa.json index f9c8255..dc3a02d 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -206,6 +206,92 @@ }, "status": "وضعیت", "title": "عنوان", + "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": "خلاصه بلاگ", + "content": "محتوا", + "blog_status": "وضعیت بلاگ", + "featured_image": "تصویر شاخص", + "tags": "برچسب ها", + "tag_hint": "جدا کردن با کاما یا کلید Enter ", + "shareDate": "تاریخ انتشار", + "enter_your_title": "عنوان بلاگ را وارد کنید", + "add_blog": "افزودن بلاگ", + "blog_category": "دسته بندی بلاگ", + "add_category": "اضافه کردن دسته بندی", + "category_status": "وضعیت دسته بندی", + "category_title": "عنوان دسته بندی", + "parent_category": "دسته بندی مادر", + "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": { "receips": "صورتحساب ها", "receip_list": "لیست صورتحساب ها", diff --git a/src/pages/ads/AdsList.tsx b/src/pages/ads/AdsList.tsx new file mode 100644 index 0000000..b7a34ba --- /dev/null +++ b/src/pages/ads/AdsList.tsx @@ -0,0 +1,127 @@ +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 AddList: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('ads.ads')} +
+ + + + +
+
+
+
+
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+ +
+ +
+
+ +
+ + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + { }} + /> + + + + +
+ + + + + + { }} + /> + + + + +
+
+
+ ) +} + +export default AddList \ 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..bc5b980 --- /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 CreateAd: 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 CreateAd \ 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..ad623e9 --- /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/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 new file mode 100644 index 0000000..60e46c1 --- /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..0b2acba --- /dev/null +++ b/src/pages/blog/CreateBlog.tsx @@ -0,0 +1,118 @@ + +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 } from 'iconsax-react' +import ImageUploader from './components/ImageUploader' +import "quill/dist/quill.snow.css"; +import Quill from 'quill'; +const CreateBlog: FC = () => { + const { t } = useTranslation('global') + useEffect(() => { + new Quill('#editor', { + theme: 'snow', + }); + new Quill('#editor2', { + theme: 'snow', + }); + }, []); + return ( +
+
+
+ {t('blog.add_blog')} +
+ +
+
+
+
+ +
+ +

{t('blog.blog_Summary')}

+
+
+
+ +

{t('blog.content')}

+
+
+
+ +
+ + +
+
+

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

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

{t('blog.category')}

+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+ +

{t('blog.tags')}

+
+ +

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

+
+ +
+
+ +
+ ) +} + +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 new file mode 100644 index 0000000..998ac91 --- /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('blog.featured_image')}

+
+
+ +

+ { + 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..7657150 --- /dev/null +++ b/src/pages/discounts/CreateDiscount.tsx @@ -0,0 +1,156 @@ +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 RadioGroup from '../../components/RadioGroup' +const CreateDiscount: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('discount.new_discount')} +
+ +
+
+
+
+ {t('discount.type')} +
+ ''} + selected={''} + /> +
+
+
+ +
+ +
+
+
+
+ {t('discount.price')} +
+ ''} + selected={''} + /> +
+
+ +
+
+ { }} + placeholder='' + defaulValue='1400-01-01' + /> + { }} + placeholder='' + defaulValue='1400-01-01' + /> +
+
+
+
+

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

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

{t('discount.availabe_service')}

+
+ +
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+ +
+
+ لورم ایپسوم +
+
+
+
+
+
+ ) +} +export default CreateDiscount \ 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..7b6ac89 --- /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 DiscountList: FC = () => { + const { t } = useTranslation('global') + return ( +
+
+
+ {t('discount.list')} +
+ + + + +
+ + + + +
+
+ +
+ +
+ +
+
+ + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + { }} + /> + + + + +
+ + + + + + + + { }} + /> + + + + +
+
+
+ ) +} + +export default DiscountList \ 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 acf0d00..5a2cd9f 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -5,6 +5,13 @@ 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 BlogCategory from '../pages/blog/BlogCategory' +import CreateAds from '../pages/ads/CreateAds' import TicketList from '../pages/ticket/TicketList' import CreateTicket from '../pages/ticket/CreateTicket' import TicketDetail from '../pages/ticket/Detail' @@ -59,6 +66,13 @@ const MainRouter: FC = () => { } /> } /> } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> } /> } />