diff --git a/package-lock.json b/package-lock.json index 160ecd2..cd0f660 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "formik": "^2.4.6", "i18next": "^24.2.0", "iconsax-react": "^0.0.8", + "rc-rate": "^2.13.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-dropzone": "^14.3.5", @@ -23,6 +24,7 @@ "react-otp-input": "^3.1.1", "react-router-dom": "^7.1.0", "react-toastify": "^11.0.2", + "swiper": "^11.2.1", "tailwind-merge": "^2.5.5", "yup": "^1.6.1", "zustand": "^5.0.2" @@ -31,6 +33,7 @@ "@eslint/js": "^9.17.0", "@types/react": "^18.3.17", "@types/react-dom": "^18.3.5", + "@types/swiper": "^5.4.3", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "eslint": "^9.17.0", @@ -1862,6 +1865,13 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/swiper": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@types/swiper/-/swiper-5.4.3.tgz", + "integrity": "sha512-hJXpVeANf+XQXgbvmuFZdsnaSOKqOEZcaLDnHhZOJDRow+lfboatwubW+Ay9XiHobMGyEomkgpXSYRlDVn4gMQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz", @@ -4110,6 +4120,44 @@ ], "license": "MIT" }, + "node_modules/rc-rate": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", + "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util": { + "version": "5.44.3", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.3.tgz", + "integrity": "sha512-q6KCcOFk3rv/zD3MckhJteZxb0VjAIFuf622B7ElK4vfrZdAzs16XR5p3VTdy3+U5jfJU5ACz4QnhLSuAGe5dA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/react": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", @@ -4673,6 +4721,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swiper": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.1.tgz", + "integrity": "sha512-62G69+iQRIfUqTmJkWpZDcX891Ra8O9050ckt1/JI2H+0483g+gq0m7gINecDqMtDh2zt5dK+uzBRxGhGOOvQA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "license": "MIT", + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", diff --git a/package.json b/package.json index 02cc76c..18cf539 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "formik": "^2.4.6", "i18next": "^24.2.0", "iconsax-react": "^0.0.8", + "rc-rate": "^2.13.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-dropzone": "^14.3.5", @@ -25,6 +26,7 @@ "react-otp-input": "^3.1.1", "react-router-dom": "^7.1.0", "react-toastify": "^11.0.2", + "swiper": "^11.2.1", "tailwind-merge": "^2.5.5", "yup": "^1.6.1", "zustand": "^5.0.2" @@ -33,6 +35,7 @@ "@eslint/js": "^9.17.0", "@types/react": "^18.3.17", "@types/react-dom": "^18.3.5", + "@types/swiper": "^5.4.3", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "eslint": "^9.17.0", diff --git a/src/App.tsx b/src/App.tsx index 0d00056..1f052ac 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,7 @@ import { FC, useEffect, useState } from 'react' import { BrowserRouter } from 'react-router-dom' +import 'swiper/css' +import 'rc-rate/assets/index.css'; import i18next from 'i18next' import { I18nextProvider } from 'react-i18next' import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query' diff --git a/src/assets/images/appimage.png b/src/assets/images/appimage.png new file mode 100644 index 0000000..6495d79 Binary files /dev/null and b/src/assets/images/appimage.png differ diff --git a/src/assets/images/share.svg b/src/assets/images/share.svg new file mode 100644 index 0000000..b5618e5 --- /dev/null +++ b/src/assets/images/share.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Radio.tsx b/src/components/Radio.tsx new file mode 100644 index 0000000..a8282af --- /dev/null +++ b/src/components/Radio.tsx @@ -0,0 +1,20 @@ +import { FC } from 'react' + +type Props = { + isActive: boolean, + value: 'year' | '3month' | 'month', + onChange: (value: 'year' | '3month' | 'month') => void +} + +const Radio: FC = (props: Props) => { + return ( +
props.onChange(props.value)} className='size-4 cursor-pointer rounded-full bg-[#EAEDF5] flex justify-center items-center'> + { + props.isActive && +
+ } +
+ ) +} + +export default Radio \ No newline at end of file diff --git a/src/components/RadioGroup.tsx b/src/components/RadioGroup.tsx new file mode 100644 index 0000000..f68c939 --- /dev/null +++ b/src/components/RadioGroup.tsx @@ -0,0 +1,31 @@ +import { FC } from 'react' +import Radio from './Radio' + + +type Props = { + items: { + label: string + value: 'year' | '3month' | 'month' + }[] + selected: string + onChange: (value: 'year' | '3month' | 'month') => void +} + +const RadioGroup: FC = (props: Props) => { + return ( +
+ { + props.items.map((item, index) => ( +
+ +
+ {item.label} +
+
+ )) + } +
+ ) +} + +export default RadioGroup \ No newline at end of file diff --git a/src/config/Pages.ts b/src/config/Pages.ts index 1973ba4..fd96843 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -8,6 +8,7 @@ export const Pages = { services: { mine: "/services", other: "/other-service", + detail: "/services/detail/", }, transactions: "/transactions", receipts: { diff --git a/src/index.css b/src/index.css index e09ea81..3643380 100644 --- a/src/index.css +++ b/src/index.css @@ -114,3 +114,7 @@ tbody tr { backdrop-filter: blur(44px); } + +.rc-rate-star { + margin-right: 3px !important; /* فاصله بین ستاره‌ها */ +} diff --git a/src/langs/fa.json b/src/langs/fa.json index 23cd1cc..41674a0 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -83,7 +83,27 @@ "active_menu": "منو فعال", "selected_danak": "انتخاب داناک", "buy": "خرید", - "other_services": "سایر سرویس ها" + "other_services": "سایر سرویس ها", + "year": "سالانه", + "month3": "۳ ماهه", + "month": "ماهیانه", + "company_develop": "شرکت توسعه دهنده", + "company_danak": "شرکت داناک", + "user_count": "تعداد کاربران", + "year_make": "سال ساخت", + "lang_app": "زبان نرم افزار", + "persian": "فارسی", + "score": "امتیاز", + "compelete_description": "توضیحات تکمیلی", + "submit_comment": "ثبت نظر", + "hint_comment": "شما پس از خرید این سرویس میتوانید نظر خود را به ثبت برسانید.", + "fullName": "نام و نام خانوادگی", + "enter_your_name": "نام خود را واردکنید", + "title": "عنوان", + "enter_title_comment": "عنوان نظر خود را وارد کنید", + "your_comment": "نظر شما", + "write_your_comment": "نظر خود را راجع به این سرویس بنویسید", + "users_comments": "نظرات کاربران" }, "footer": { "home": "صفحه اصلی", diff --git a/src/pages/notification/Notification.tsx b/src/pages/notification/Notification.tsx index f1c6f60..5682255 100644 --- a/src/pages/notification/Notification.tsx +++ b/src/pages/notification/Notification.tsx @@ -19,7 +19,7 @@ const Notifications: FC = () => { { showModal && ( -
+
{t('notif.natification')} diff --git a/src/pages/service/DetailService.tsx b/src/pages/service/DetailService.tsx new file mode 100644 index 0000000..5d9850f --- /dev/null +++ b/src/pages/service/DetailService.tsx @@ -0,0 +1,214 @@ +import { FC } from 'react' +import RobotImage from '../../assets/images/robot.jpeg' +import { SIDEBAR_SIZE_LEFT } from '../../config/Const' +import { useTranslation } from 'react-i18next' +import Button from '../../components/Button' +import Rate from 'rc-rate' +import ServiceImages from './components/ServiceImages' +import Input from '../../components/Input' +import Textarea from '../../components/Textarea' +import AvatarImage from '../../assets/images/Avatar.png' +import ServiceHeader from './components/ServiceHeader' + +const DetailService: FC = () => { + + const { t } = useTranslation('global') + + return ( +
+ +
+ + +
+
+
+ {t('service.company_develop')} +
+
+ {t('service.company_danak')} +
+
+
+
+ {t('service.user_count')} +
+
+ +۵۰۰ +
+
+
+
+ {t('service.year_make')} +
+
+ ۱۴۰۰ +
+
+
+
+ {t('service.lang_app')} +
+
+ {t('service.persian')} +
+
+
+
+ {t('service.score')} +
+
+ +
+
+
+ + + +
+
+ {t('service.compelete_description')} +
+

+ لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است، چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است، و برای شرایط فعلی تکنولوژی مورد نیاز، و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد، کتابهای زیادی در شصت و سه درصد گذشته حال و آینده، شناخت فراوان جامعه و متخصصان را می طلبد، تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی، و فرهنگ پیشرو در زبان فارسی ایجاد کرد، در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها، و شرایط سخت تایپ به پایان رسد و زمان مورد نیاز شامل حروفچینی دستاوردهای اصلی، و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد. +

+
+ +
+
+
+ {t('service.submit_comment')} +
+
+ {t('service.hint_comment')} +
+ +
+
+ {t('service.score')} +
+
+ +
+ +
+ +
+
+ +
+ +
+