├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── README.md ├── additional.d.ts ├── components ├── ErrorBoundary │ └── index.tsx ├── ImageComponent │ └── index.tsx ├── attribute │ ├── attribute-delete-view.tsx │ ├── attribute-form.tsx │ └── attribute-list.tsx ├── auth │ ├── change-password-from.tsx │ ├── forget-password │ │ ├── enter-email-view.tsx │ │ ├── enter-new-password-view.tsx │ │ ├── enter-token-view.tsx │ │ └── forget-password.tsx │ ├── login-form.tsx │ └── profile-update-form.tsx ├── category │ ├── category-form.tsx │ ├── category-icons.ts │ ├── category-list.tsx │ └── category-validation-schema.ts ├── common │ ├── access-denied.tsx │ ├── action-buttons.tsx │ ├── avatar.tsx │ ├── card.tsx │ ├── confirmation-card.tsx │ ├── notification-menu.tsx │ ├── search.tsx │ ├── sort-form.tsx │ └── uploader.tsx ├── dashboard │ └── index.tsx ├── hero-carousel │ ├── hero-banner-card.tsx │ ├── hero-carousel-list.tsx │ ├── hero-slide-form.tsx │ ├── hero-slider-validation-schema.ts │ └── slider-delete-view.tsx ├── icons │ ├── add.tsx │ ├── arrow-down.tsx │ ├── arrow-next.tsx │ ├── arrow-prev.tsx │ ├── arrow-up.tsx │ ├── ban-user.tsx │ ├── bell.tsx │ ├── cart-icon-bag.tsx │ ├── category │ │ ├── accessories.tsx │ │ ├── bath-oil.tsx │ │ ├── beauty-health.tsx │ │ ├── bed.tsx │ │ ├── beverage.tsx │ │ ├── book-shelf.tsx │ │ ├── breakfast.tsx │ │ ├── center-table.tsx │ │ ├── chair.tsx │ │ ├── cooking.tsx │ │ ├── dairy.tsx │ │ ├── deodorant.tsx │ │ ├── dressing-table.tsx │ │ ├── eyes.tsx │ │ ├── face.tsx │ │ ├── facial-care.tsx │ │ ├── fruits-vegetable.tsx │ │ ├── hand-bag.tsx │ │ ├── home-cleaning.tsx │ │ ├── index.tsx │ │ ├── laptop-bag.tsx │ │ ├── lips.tsx │ │ ├── meat-fish.tsx │ │ ├── oral-care.tsx │ │ ├── outer-wear.tsx │ │ ├── pants.tsx │ │ ├── pet-care.tsx │ │ ├── purse.tsx │ │ ├── reading-table.tsx │ │ ├── relax-chair.tsx │ │ ├── shaving-needs.tsx │ │ ├── shirts.tsx │ │ ├── shoulder-bag.tsx │ │ ├── skirts.tsx │ │ ├── snacks.tsx │ │ ├── sofa.tsx │ │ ├── storage.tsx │ │ ├── table.tsx │ │ ├── tools.tsx │ │ ├── tops.tsx │ │ ├── wallet.tsx │ │ └── women-dress.tsx │ ├── checkmark-circle-fill.tsx │ ├── checkmark-circle.tsx │ ├── checkmark.tsx │ ├── close-fill.tsx │ ├── close-icon.tsx │ ├── coin-icon.tsx │ ├── copy.tsx │ ├── coupon-icon.tsx │ ├── delivery-icon.tsx │ ├── dot.tsx │ ├── download-icon.tsx │ ├── edit copy.tsx │ ├── edit.tsx │ ├── expand-less-icon.tsx │ ├── expand-more-icon.tsx │ ├── eye-icon.tsx │ ├── eye-off-icon.tsx │ ├── ios-arrow-down.tsx │ ├── ios-arrow-up.tsx │ ├── map-pin.tsx │ ├── members-icon.tsx │ ├── minus.tsx │ ├── more-icon.tsx │ ├── navbar-icon.tsx │ ├── order-icon.tsx │ ├── phone.tsx │ ├── product-icon.tsx │ ├── refund.tsx │ ├── revenue.tsx │ ├── save-icon.tsx │ ├── search-icon.tsx │ ├── shops │ │ ├── cube.tsx │ │ ├── dollar.tsx │ │ ├── grocery-basket.tsx │ │ ├── percentage.tsx │ │ └── price-wallet.tsx │ ├── sidebar-category-icon.tsx │ ├── sidebar │ │ ├── affiliate.tsx │ │ ├── apps.tsx │ │ ├── attribute-value.tsx │ │ ├── attribute.tsx │ │ ├── categories.tsx │ │ ├── coupons.tsx │ │ ├── dashboard.tsx │ │ ├── image-multiple.tsx │ │ ├── index.tsx │ │ ├── my-shop.tsx │ │ ├── order-status.tsx │ │ ├── orders.tsx │ │ ├── products.tsx │ │ ├── settings.tsx │ │ ├── shippings.tsx │ │ ├── shop.tsx │ │ ├── staffs.tsx │ │ ├── suppliers.tsx │ │ ├── support.tsx │ │ ├── tags.tsx │ │ ├── taxes.tsx │ │ ├── types.tsx │ │ ├── users.tsx │ │ └── withdraw.tsx │ ├── site-settings-icon.tsx │ ├── social │ │ ├── facebook.tsx │ │ ├── index.tsx │ │ ├── instagram.tsx │ │ ├── twitter.tsx │ │ └── youtube.tsx │ ├── trash.tsx │ ├── type │ │ ├── bakery-icon.tsx │ │ ├── book-icon.tsx │ │ ├── dress-icon.tsx │ │ ├── facial-care.tsx │ │ ├── fruits-vegetable.tsx │ │ ├── furniture-icon.tsx │ │ ├── handbag-icon.tsx │ │ ├── index.tsx │ │ ├── medicine-icon.tsx │ │ └── restaurant-icon.tsx │ ├── upload-icon copy.tsx │ ├── upload-icon.tsx │ └── user-icon.tsx ├── layouts │ └── app.tsx ├── navigation │ ├── index.tsx │ ├── menu.tsx │ ├── mobile-navigation.tsx │ ├── navbar.tsx │ ├── scss │ │ └── index.module.scss │ └── sidebar │ │ ├── index.tsx │ │ ├── sidebar-item-mini.tsx │ │ ├── sidebar-item.tsx │ │ └── sidebar-mini.tsx ├── order │ ├── invoice-pdf.tsx │ ├── order-list.tsx │ └── recent-orders.tsx ├── product │ ├── product-category-input.tsx │ ├── product-delete-view.tsx │ ├── product-form.tsx │ ├── product-info-form.tsx │ ├── product-list.tsx │ ├── product-validation-schema.ts │ ├── product-variable-form │ │ ├── cartesian-product-component.tsx │ │ ├── index.tsx │ │ └── variation-images.tsx │ ├── variablesSubmission.ts │ └── variations-reducer.ts ├── settings │ ├── settings-form.tsx │ └── settings-validation-schema.ts ├── staff │ ├── staff-ban-view.tsx │ ├── staff-delete-view.tsx │ ├── staff-form.tsx │ ├── staff-list.tsx │ └── staff-validation-schema.ts ├── ui │ ├── activeLink.tsx │ ├── alert.tsx │ ├── badge │ │ └── badge.tsx │ ├── button.tsx │ ├── chart.tsx │ ├── checkbox │ │ ├── checkbox.module.css │ │ └── index.tsx │ ├── color-picker │ │ ├── color-picker.tsx │ │ └── display-color-code.tsx │ ├── date-picker.tsx │ ├── default-seo.tsx │ ├── description.tsx │ ├── drawer-wrapper.tsx │ ├── drawer.tsx │ ├── editor │ │ ├── editor.tsx │ │ └── index.tsx │ ├── error-message.tsx │ ├── file-input.tsx │ ├── form-validation-error.tsx │ ├── form │ │ └── form.tsx │ ├── import-csv.tsx │ ├── input-phone-number.tsx │ ├── input.tsx │ ├── label.tsx │ ├── link-button.tsx │ ├── link.tsx │ ├── loader │ │ ├── loader.module.css │ │ └── loader.tsx │ ├── loading-bar │ │ ├── index.tsx │ │ └── loading-bar.module.scss │ ├── loading-progress │ │ ├── index.tsx │ │ └── loading-bar.module.scss │ ├── logo.tsx │ ├── modal │ │ ├── managed-modal.tsx │ │ ├── modal.context.tsx │ │ └── modal.tsx │ ├── notification-card.tsx │ ├── page-loader │ │ ├── page-loader.module.css │ │ └── page-loader.tsx │ ├── pagination.tsx │ ├── password-input.tsx │ ├── progress-box │ │ ├── progress-box.module.css │ │ └── progress-box.tsx │ ├── radio-card │ │ ├── radio-card.module.css │ │ └── radio-card.tsx │ ├── radio │ │ ├── index.tsx │ │ └── radio.module.css │ ├── scrollable-content.tsx │ ├── scrollbar.tsx │ ├── select-input.tsx │ ├── select │ │ ├── select.styles.ts │ │ └── select.tsx │ ├── sidebar-menu.tsx │ ├── switch-input.tsx │ ├── table.tsx │ ├── text-area.tsx │ ├── title.tsx │ ├── truncate-scroll.tsx │ └── truncate.tsx └── widgets │ ├── column-chart.tsx │ ├── donut-chart.tsx │ ├── gradient-graph-chart.tsx │ ├── graph-chart.tsx │ ├── line-chart.tsx │ ├── map-widget.tsx │ ├── radial-bar-bhart.tsx │ └── sticker-card.tsx ├── contexts ├── settings.context.tsx ├── staff.context.tsx ├── time.context.tsx └── ui.context.tsx ├── hooks ├── index.ts ├── use-price.ts ├── use-store.ts ├── useErrorLogger.ts ├── useGetStaff.ts ├── useId.tsx ├── useLocalStorage.ts ├── useMediaQuery.ts ├── useStorage.ts ├── useTime.ts ├── useWarnIfUnsavedChanges.ts └── use_percent-decrease.ts ├── init.sql ├── jest.config.js ├── jest.setup.js ├── lib ├── S3 │ ├── Date.ts │ ├── ErrorThrower.ts │ ├── Policy.ts │ ├── Signature.ts │ ├── react-aws-s3.ts │ └── types.ts ├── ca-certificate.crt ├── conn.ts ├── database.ts ├── index.ts ├── notify.ts ├── sentry.ts └── sql │ ├── attribute.sql.ts │ ├── carousel.sql.ts │ ├── category.sql.ts │ ├── coupon.sql.ts │ ├── dashboard.sql.ts │ ├── index.ts │ ├── login.sql.ts │ ├── order.sql.ts │ ├── orderStatus.sql.ts │ ├── product.sql.ts │ ├── settings.sql.ts │ ├── shipping.sql.ts │ ├── staff.sql.ts │ ├── supplier.sql.ts │ └── tag.sql.ts ├── middleware.ts ├── middleware ├── jwt.keys.ts ├── jwtRS256.key.pub └── utils.ts ├── next-env.d.ts ├── next-i18next.config.js ├── next.config.js ├── package.json ├── pages ├── [slug].tsx ├── _app.tsx ├── _document.tsx ├── _error.js ├── admin │ ├── attributes │ │ ├── create.tsx │ │ ├── edit │ │ │ └── [attributeId].tsx │ │ └── index.tsx │ ├── categories │ │ ├── create.tsx │ │ ├── edit │ │ │ └── [categoryId].tsx │ │ └── index.tsx │ ├── dashboard.tsx │ ├── hero-carousel │ │ ├── create.tsx │ │ ├── edit │ │ │ └── [sliderId].tsx │ │ └── index.tsx │ ├── login.tsx │ ├── logout.tsx │ ├── orders │ │ ├── [orderId] │ │ │ └── index.tsx │ │ └── index.tsx │ ├── products │ │ ├── create.tsx │ │ ├── edit │ │ │ └── [productId].tsx │ │ └── index.tsx │ ├── settings │ │ └── index.tsx │ └── staffs │ │ ├── create.tsx │ │ ├── edit │ │ └── [staffId].tsx │ │ └── index.tsx ├── api │ ├── admin │ │ ├── attribute │ │ │ ├── [id].ts │ │ │ ├── attributes │ │ │ │ ├── [page].ts │ │ │ │ └── select │ │ │ │ │ └── all.ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── update.ts │ │ │ └── value │ │ │ │ └── delete.ts │ │ ├── banner │ │ │ ├── [id].ts │ │ │ ├── banners │ │ │ │ └── index.ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ └── update.ts │ │ ├── category │ │ │ ├── [id].ts │ │ │ ├── categories │ │ │ │ ├── [page].ts │ │ │ │ └── select │ │ │ │ │ ├── [id].ts │ │ │ │ │ ├── all.ts │ │ │ │ │ └── index.ts │ │ │ ├── create.ts │ │ │ └── update.ts │ │ ├── dashboard │ │ │ └── index.ts │ │ ├── media │ │ │ └── delete.ts │ │ ├── order │ │ │ ├── [id].ts │ │ │ ├── orders │ │ │ │ └── [page].ts │ │ │ └── update-status.ts │ │ ├── product │ │ │ ├── [id].ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── products │ │ │ │ └── [page].ts │ │ │ └── update.ts │ │ ├── settings │ │ │ ├── index.ts │ │ │ └── update.ts │ │ └── staff │ │ │ ├── [id].ts │ │ │ ├── block.ts │ │ │ ├── create.ts │ │ │ ├── delete.ts │ │ │ ├── login.ts │ │ │ ├── staffs │ │ │ └── [page].ts │ │ │ └── update.ts │ ├── order.ts │ └── store │ │ ├── category-request │ │ └── [name].ts │ │ ├── home-request.ts │ │ └── product │ │ └── [slug].ts ├── category │ └── [name].tsx ├── faq.tsx ├── index.tsx └── terms.tsx ├── postcss.config.js ├── public ├── arrow-next.svg ├── arrow-previous.svg ├── category-placeholder.jpg ├── favicons │ ├── android-chrome-192x192.png │ ├── android-chrome-256x256.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── mstile-150x150.png │ └── safari-pinned-tab.svg ├── icons │ ├── apple-icon-180.png │ ├── manifest-icon-192.png │ └── manifest-icon-512.png ├── image │ ├── card-argon.png │ ├── card-helium.png │ ├── card-krypton.png │ ├── card-neon.png │ ├── card-xenon.png │ ├── layout-classic.png │ ├── layout-modern.png │ └── layout-standard.png ├── locales │ ├── ar │ │ ├── banner.json │ │ ├── common.json │ │ ├── form.json │ │ ├── table.json │ │ └── widgets.json │ ├── en │ │ ├── banner.json │ │ ├── common.json │ │ ├── error.json │ │ ├── form.json │ │ ├── table.json │ │ └── widgets.json │ └── fr │ │ ├── banner.json │ │ ├── common.json │ │ ├── form.json │ │ ├── table.json │ │ └── widgets.json ├── logo.svg ├── manifest.json ├── placeholders │ ├── avatar.jpg │ ├── avatar.svg │ ├── avatar__placeholder.png │ ├── image.jpg │ ├── image__placeholder.png │ └── no-image.svg ├── robots.txt ├── shop.jpg ├── sw.js └── workbox-4a677df8.js ├── redux ├── card │ └── index.ts └── index.ts ├── settings ├── seo.settings.ts └── site.settings.ts ├── store ├── assets │ ├── icons │ │ ├── arrow-left.tsx │ │ ├── arrow-right.tsx │ │ ├── cart-icon.tsx │ │ ├── categories.tsx │ │ ├── chevron-down.tsx │ │ ├── chevron-left.tsx │ │ ├── chevron-right.tsx │ │ ├── close.tsx │ │ ├── empty-svg.tsx │ │ ├── home.tsx │ │ ├── medi-icon-one.tsx │ │ ├── medi-icon-three.tsx │ │ ├── medi-icon-two.tsx │ │ ├── minus-icon.tsx │ │ ├── not-found.tsx │ │ ├── phone.tsx │ │ ├── plus-icon.tsx │ │ ├── quote.tsx │ │ ├── search-icon.tsx │ │ ├── social-icons.tsx │ │ ├── success-tick.tsx │ │ └── trash.tsx │ ├── image │ │ ├── fb.svg │ │ ├── git.svg │ │ ├── hero-banner-img.jpg │ │ ├── inst.svg │ │ ├── link.svg │ │ ├── twt.svg │ │ └── ytb.svg │ └── styles │ │ ├── index.css │ │ ├── rc-collapse.css │ │ └── scrollbar.css ├── components │ ├── CategoryHeader.tsx │ ├── CategorySlider.tsx │ ├── accordion.tsx │ ├── active-link.tsx │ ├── animated-counter.tsx │ ├── banner.tsx │ ├── breadcrumb.tsx │ ├── button.tsx │ ├── carousel │ │ ├── carousel.tsx │ │ ├── slider.tsx │ │ └── thumbnail-carousel.tsx │ ├── cart-item.tsx │ ├── counter.tsx │ ├── feature-block.tsx │ ├── icon-button.tsx │ ├── input.tsx │ ├── instagram-card.tsx │ ├── item-card.tsx │ ├── scrollbar.tsx │ ├── search-outline.tsx │ ├── search.tsx │ ├── section-title.tsx │ ├── testimonial-carousel.tsx │ ├── textarea.tsx │ └── utils │ │ ├── prop-types.ts │ │ └── theme.ts ├── containers │ ├── banner │ │ ├── hero-banner-card.tsx │ │ └── hero-block.tsx │ ├── drawer │ │ ├── drawer.tsx │ │ └── views │ │ │ ├── cart.tsx │ │ │ ├── checkout.tsx │ │ │ ├── menus.tsx │ │ │ ├── no-item.tsx │ │ │ └── order-submit.tsx │ ├── how-it-works.tsx │ ├── instagram-review.tsx │ ├── layout │ │ ├── footer.tsx │ │ ├── header.tsx │ │ ├── layout.tsx │ │ └── menu │ │ │ └── index.tsx │ ├── product │ │ ├── ProductTopSells.tsx │ │ ├── attribute-value-label.tsx │ │ ├── product-attributes.tsx │ │ ├── product-details.tsx │ │ └── variation-price.tsx │ ├── products.tsx │ └── term │ │ ├── data.ts │ │ └── terms.tsx ├── contexts │ ├── drawer │ │ └── drawer.provider.tsx │ ├── search │ │ └── use-search.tsx │ └── sticky │ │ └── sticky.provider.tsx └── helpers │ ├── constants.tsx │ ├── get-initials-or-option.tsx │ ├── get-products.tsx │ ├── use-media.ts │ ├── use-ref-scroll.tsx │ ├── use-searchable.tsx │ ├── use-storage.tsx │ └── useOnClickOutside.tsx ├── styles ├── color-picker.module.css ├── custom-classes.css ├── custom-plugins.css └── main.css ├── tailwind.config.js ├── ts-types ├── constants.ts ├── custom.types.ts ├── enums.ts ├── generated.ts └── index.ts ├── tsconfig.json ├── utils ├── api │ ├── endpoints.ts │ └── http.ts ├── auth-utils.ts ├── cartesian.ts ├── constants.ts ├── cookies.ts ├── currency.ts ├── data-mappers.ts ├── form-error.tsx ├── format-address.tsx ├── is-loggedin.ts ├── locals.tsx ├── motion │ ├── fade-in-left.ts │ ├── fade-in-out.ts │ ├── fade-in-right.ts │ ├── height-collapse.ts │ ├── zoom-in-bottom.ts │ ├── zoom-in-out.ts │ └── zoom-out-in.ts ├── parse-cookie.ts ├── private-route.tsx ├── routes.ts ├── use-breadcrumb.ts ├── use-click-outside.ts ├── use-price.ts └── utils.ts └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | .next 2 | .now 3 | .vercel 4 | node_modules 5 | .vscode 6 | .husky 7 | .github 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['simple-import-sort'], 3 | root: true, 4 | parserOptions: { 5 | ecmaVersion: 2020, 6 | sourceType: 'module', 7 | warnOnUnsupportedTypeScriptVersion: false, 8 | ecmaFeatures: { 9 | jsx: true 10 | } 11 | }, 12 | settings: { 13 | react: { 14 | version: 'detect' 15 | } 16 | }, 17 | env: { 18 | browser: true, 19 | amd: true, 20 | node: true 21 | }, 22 | extends: [ 23 | 'next', 24 | 'next/core-web-vitals', 25 | 'eslint:recommended', 26 | 'plugin:jsx-a11y/recommended' 27 | ], 28 | rules: { 29 | 'simple-import-sort/imports': 'error', 30 | 'simple-import-sort/exports': 'error', 31 | 'react/react-in-jsx-scope': 'off', 32 | 'jsx-a11y/anchor-is-valid': [ 33 | 'error', 34 | { 35 | components: ['Link'], 36 | specialLink: ['hrefLeft', 'hrefRight'], 37 | aspects: ['invalidHref', 'preferButton'] 38 | } 39 | ] 40 | }, 41 | overrides: [ 42 | Object.assign( 43 | { 44 | files: ['**/__tests__/*-spec.tsx', '**/__mocks__/*.ts'], 45 | env: { jest: true }, 46 | plugins: ['jest'] 47 | }, 48 | require('eslint-plugin-jest').configs.recommended 49 | ) 50 | ] 51 | }; 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | tsconfig.tsbuildinfo 8 | 9 | # volumes 10 | /web-root/ 11 | /dhparam/ 12 | /pgadmin/ 13 | /database/ 14 | 15 | # testing 16 | /coverage 17 | 18 | # next.js 19 | /.next/ 20 | /out/ 21 | .vscode 22 | 23 | # production 24 | /build 25 | 26 | # misc 27 | .DS_Store 28 | *.pem 29 | 30 | # debug 31 | npm-debug.log* 32 | yarn-debug.log* 33 | yarn-error.log* 34 | 35 | # local env files 36 | .env 37 | .env.local 38 | .env.development.local 39 | .env.test.local 40 | .env.production.local 41 | 42 | # vercel 43 | .vercel 44 | 45 | .vercel 46 | 47 | # Sentry 48 | .sentryclirc 49 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | echo '🏗️👷 Styling, testing and building your project before committing' 5 | 6 | # Check Prettier standards 7 | # yarn check-format || 8 | # ( 9 | # echo '🤢🤮🤢🤮 Its FOKING RAW - Your styling looks disgusting. 🤢🤮🤢🤮 10 | # Prettier Check Failed. Run yarn format, add changes and try commit again.' 11 | # false 12 | # ) 13 | 14 | # Check ESLint Standards 15 | # yarn lint || 16 | # ( 17 | # echo '😤🏀👋😤 Get that weak shit out of here! 😤🏀👋😤 18 | # ESLint Check Failed. Make the required changes listed above, add changes and try to commit again.' 19 | # false 20 | # ) 21 | 22 | # Check tsconfig standards 23 | # yarn check-types || 24 | # ( 25 | # echo '🤡😂❌🤡 Failed Type check. 🤡😂❌🤡 26 | # Are you seriously trying to write that? Make the changes required above.' 27 | # false 28 | # ) 29 | 30 | # If everything passes... Now we can commit 31 | echo '🤔🤔🤔🤔... Alright.... Code looks good to me... Trying to build now. 🤔🤔🤔🤔' 32 | 33 | # yarn build || 34 | # ( 35 | # echo '❌👷🔨❌ Better call Bob... Because your build failed ❌👷🔨❌ 36 | # Next build failed: View the errors above to see why.' 37 | # false 38 | # ) 39 | 40 | # If everything passes... Now we can commit 41 | echo '✅✅✅✅ You win this time... I am committing this now. ✅✅✅✅' 42 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | .now 3 | .vercel 4 | .storybook 5 | coverage 6 | node_modules 7 | next-env.d.ts 8 | yarn.lock 9 | ./utils/cities.min.json 10 | utils/cities.min.json 11 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false, 10 | "arrowParens": "always", 11 | "proseWrap": "always" 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ------------------------ 2 | Generate jwt public and private keys 3 | 4 | ```bash 5 | ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key 6 | # Don't add passphrase 7 | openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub 8 | cat jwtRS256.key 9 | cat jwtRS256.key.pub 10 | ``` 11 | ![a8b0c33805b754a71792c0f8ba71c59f2b8603ee](https://user-images.githubusercontent.com/52937392/226219836-bb40f0c1-7010-49b6-8a35-3d1726fc2e79.png) 12 | 13 | 14 | ![4a7132c7e0833d72746fb3ad1bdac97f7705ee2b (1)](https://user-images.githubusercontent.com/52937392/226219839-e994a387-c7b9-4a4c-b00e-4bedb242bcd2.png) 15 | 16 | -------------------------------------------------------------------------------- /additional.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | interface Number { 3 | toCommas(): string; 4 | secondsToHm(): string; 5 | } 6 | -------------------------------------------------------------------------------- /components/ErrorBoundary/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class ErrorBoundary extends React.Component { 4 | constructor(props) { 5 | super(props); 6 | 7 | // Define a state variable to track whether is an error or not 8 | this.state = { hasError: false }; 9 | } 10 | // eslint-disable-next-line no-unused-vars 11 | static getDerivedStateFromError(error) { 12 | // Update state so the next render will show the fallback UI 13 | 14 | return { hasError: true }; 15 | } 16 | componentDidCatch(error, errorInfo) { 17 | // You can use your own error logging service here 18 | console.log({ error, errorInfo }); 19 | } 20 | render() { 21 | // Check if the error is thrown 22 | if ((this.state as { hasError: boolean }).hasError) { 23 | // You can render any custom fallback UI 24 | return ( 25 |
26 |

Oops, there is an error!

27 | 33 |
34 | ); 35 | } 36 | 37 | // Return children components in case of no error 38 | 39 | return this.props.children; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /components/ImageComponent/index.tsx: -------------------------------------------------------------------------------- 1 | import Image, { ImageProps } from 'next/image'; 2 | import React, { memo } from 'react'; 3 | 4 | const ImageComponent = (props: ImageProps) => { 5 | const Base64Placeholder = 6 | 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+utrPQAJNQNlcqdyCgAAAABJRU5ErkJggg=='; 7 | 8 | return ( 9 | {props.alt} 15 | ); 16 | }; 17 | 18 | export default memo(ImageComponent); 19 | -------------------------------------------------------------------------------- /components/auth/forget-password/enter-email-view.tsx: -------------------------------------------------------------------------------- 1 | import Button from '@components/ui/button'; 2 | import Input from '@components/ui/input'; 3 | import { useForm } from 'react-hook-form'; 4 | import { yupResolver } from '@hookform/resolvers/yup'; 5 | import * as yup from 'yup'; 6 | import { useTranslation } from 'next-i18next'; 7 | interface Props { 8 | onSubmit: (values: { email: string }) => void; 9 | loading: boolean; 10 | } 11 | const schema = yup.object().shape({ 12 | email: yup 13 | .string() 14 | .email('form:error-email-format') 15 | .required('form:error-email-required') 16 | }); 17 | 18 | const EnterEmailView = ({ onSubmit, loading }: Props) => { 19 | const { t } = useTranslation(); 20 | const { 21 | register, 22 | handleSubmit, 23 | 24 | formState: { errors } 25 | } = useForm<{ email: string }>({ resolver: yupResolver(schema) }); 26 | 27 | return ( 28 |
29 | 38 | 41 |
42 | ); 43 | }; 44 | 45 | export default EnterEmailView; 46 | -------------------------------------------------------------------------------- /components/auth/forget-password/enter-new-password-view.tsx: -------------------------------------------------------------------------------- 1 | import Button from '@components/ui/button'; 2 | import PasswordInput from '@components/ui/password-input'; 3 | import { useForm } from 'react-hook-form'; 4 | import { yupResolver } from '@hookform/resolvers/yup'; 5 | import * as yup from 'yup'; 6 | import { useTranslation } from 'next-i18next'; 7 | interface Props { 8 | onSubmit: (values: { password: string }) => void; 9 | loading: boolean; 10 | } 11 | const schema = yup.object().shape({ 12 | password: yup.string().required('form:error-password-required') 13 | }); 14 | 15 | const EnterNewPasswordView = ({ onSubmit, loading }: Props) => { 16 | const { t } = useTranslation(); 17 | const { 18 | register, 19 | handleSubmit, 20 | formState: { errors } 21 | } = useForm<{ password: string }>({ resolver: yupResolver(schema) }); 22 | 23 | return ( 24 |
25 | 32 | 33 | 36 | 37 | ); 38 | }; 39 | 40 | export default EnterNewPasswordView; 41 | -------------------------------------------------------------------------------- /components/auth/forget-password/enter-token-view.tsx: -------------------------------------------------------------------------------- 1 | import Button from '@components/ui/button'; 2 | import Input from '@components/ui/input'; 3 | import { useForm } from 'react-hook-form'; 4 | import { yupResolver } from '@hookform/resolvers/yup'; 5 | import * as yup from 'yup'; 6 | import { useTranslation } from 'next-i18next'; 7 | interface Props { 8 | onSubmit: (values: { token: string }) => void; 9 | loading: boolean; 10 | } 11 | const schema = yup.object().shape({ 12 | token: yup.string().required('form:error-token-required') 13 | }); 14 | 15 | const EnterTokenView = ({ onSubmit, loading }: Props) => { 16 | const { t } = useTranslation(); 17 | const { 18 | register, 19 | handleSubmit, 20 | formState: { errors } 21 | } = useForm<{ token: string }>({ resolver: yupResolver(schema) }); 22 | 23 | return ( 24 |
25 | 32 | 35 |
36 | ); 37 | }; 38 | 39 | export default EnterTokenView; 40 | -------------------------------------------------------------------------------- /components/category/category-validation-schema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | 3 | export const categoryValidationSchema = yup.object().shape({ 4 | name: yup.string().required('form:error-name-required') 5 | }); 6 | -------------------------------------------------------------------------------- /components/common/access-denied.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@components/ui/link'; 2 | import Image from 'next/image'; 3 | import { useTranslation } from 'next-i18next'; 4 | 5 | const AccessDeniedPage = () => { 6 | const { t } = useTranslation('common'); 7 | 8 | return ( 9 |
10 |
11 | {t('text-access-denied')} 16 |
17 | 18 |

19 | {t('text-access-denied')} 20 |

21 |

22 | {t('text-access-denied-message')} 23 | 24 | 28 | {t('text-return-home')} 29 | 30 |

31 |
32 | ); 33 | }; 34 | 35 | export default AccessDeniedPage; 36 | -------------------------------------------------------------------------------- /components/common/avatar.tsx: -------------------------------------------------------------------------------- 1 | // import Image from 'next/image'; 2 | import ImageComponent from '@components/ImageComponent/index'; 3 | import cn from 'classnames'; 4 | import React from 'react'; 5 | 6 | type AvatarProps = { 7 | className?: string; 8 | src: string; 9 | alt?: string; 10 | width?: number; 11 | height?: number; 12 | }; 13 | 14 | const Avatar: React.FC = ({ 15 | src, 16 | className, 17 | alt = 'Avatar', 18 | ...rest 19 | }) => { 20 | return ( 21 |
28 | 35 |
36 | ); 37 | }; 38 | 39 | export default Avatar; 40 | -------------------------------------------------------------------------------- /components/common/card.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'classnames'; 2 | import React from 'react'; 3 | 4 | type Props = { 5 | className?: string; 6 | [key: string]: unknown; 7 | }; 8 | 9 | const Card: React.FC = ({ className, ...props }) => { 10 | return
; 11 | }; 12 | 13 | export default Card; 14 | -------------------------------------------------------------------------------- /components/hero-carousel/hero-slider-validation-schema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | 3 | export const categoryValidationSchema = yup.object().shape({ 4 | // name: yup.string().required('form:error-name-required'), 5 | // icon: yup.object().nullable().required('form:error-icon-required') 6 | }); 7 | -------------------------------------------------------------------------------- /components/icons/add.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Add = ({ 4 | color = 'currentColor', 5 | width = '12px', 6 | height = '12px', 7 | ...props 8 | }) => { 9 | return ( 10 | 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /components/icons/arrow-down.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const ArrowDown = ({ 3 | color = 'currentColor', 4 | width = '12px', 5 | height = '12px', 6 | ...props 7 | }) => { 8 | return ( 9 | 16 | 22 | 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /components/icons/arrow-next.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowNext = ({ ...props }) => { 2 | return ( 3 | 9 | 14 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /components/icons/arrow-prev.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowPrev = ({ ...props }) => { 2 | return ( 3 | 9 | 14 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /components/icons/arrow-up.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const ArrowUp = ({ 3 | color = 'currentColor', 4 | width = '12px', 5 | height = '12px', 6 | ...props 7 | }) => { 8 | return ( 9 | 16 | 22 | 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /components/icons/ban-user.tsx: -------------------------------------------------------------------------------- 1 | export const BanUser = ({ ...props }) => { 2 | return ( 3 | 9 | 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /components/icons/bell.tsx: -------------------------------------------------------------------------------- 1 | export const Bell = ({ ...props }) => { 2 | return ( 3 | 4 | 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /components/icons/category/accessories.tsx: -------------------------------------------------------------------------------- 1 | export const Accessories: React.FC> = (props) => { 2 | return ( 3 | 4 | 5 | 9 | 13 | 17 | 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /components/icons/category/bed.tsx: -------------------------------------------------------------------------------- 1 | export const Bed: React.FC> = (props) => ( 2 | 10 | 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /components/icons/category/hand-bag.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const HandBags: React.FC> = (props) => { 3 | return ( 4 | 11 | 12 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /components/icons/category/laptop-bag.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const LaptopBags: React.FC> = (props) => { 3 | return ( 4 | 11 | 12 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /components/icons/category/lips.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const Lips: React.FC> = (props) => { 3 | return ( 4 | 11 | 12 | 16 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /components/icons/category/wallet.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const Wallet: React.FC> = (props) => { 3 | return ( 4 | 11 | 12 | 16 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /components/icons/checkmark-circle-fill.tsx: -------------------------------------------------------------------------------- 1 | export const CheckMarkFill = ({ ...props }) => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /components/icons/checkmark-circle.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const CheckMarkCircle = ({ ...props }) => { 3 | return ( 4 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /components/icons/checkmark.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const CheckMark = ({ ...props }) => { 3 | return ( 4 | 11 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /components/icons/close-fill.tsx: -------------------------------------------------------------------------------- 1 | export const CloseFillIcon: React.FC> = (props) => ( 2 | 7 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /components/icons/close-icon.tsx: -------------------------------------------------------------------------------- 1 | export const CloseIcon: React.FC> = (props) => ( 2 | 8 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /components/icons/copy.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const CopyIcon = (props) => { 3 | return ( 4 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /components/icons/dot.tsx: -------------------------------------------------------------------------------- 1 | export const Dot = ({ ...props }) => { 2 | return ( 3 | 10 | 11 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /components/icons/download-icon.tsx: -------------------------------------------------------------------------------- 1 | export const DownloadIcon = ({ ...rest }) => { 2 | return ( 3 | 8 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /components/icons/edit copy.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const EditIcon = ({ ...props }) => { 4 | return ( 5 | 11 | 12 | 16 | 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /components/icons/edit.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Edit = ({ ...props }) => { 4 | return ( 5 | 11 | 12 | 16 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default Edit; 26 | -------------------------------------------------------------------------------- /components/icons/expand-less-icon.tsx: -------------------------------------------------------------------------------- 1 | export const ExpandLessIcon = () => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/expand-more-icon.tsx: -------------------------------------------------------------------------------- 1 | export const ExpandMoreIcon = () => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/eye-icon.tsx: -------------------------------------------------------------------------------- 1 | export const Eye: React.FC> = (props) => ( 2 | 9 | 15 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /components/icons/eye-off-icon.tsx: -------------------------------------------------------------------------------- 1 | export const EyeOff: React.FC> = (props) => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/ios-arrow-down.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const IosArrowDown = ({ 3 | color = 'currentColor', 4 | width = '7px', 5 | height = '10px', 6 | ...props 7 | }) => { 8 | return ( 9 | 16 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /components/icons/ios-arrow-up.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const IosArrowUp = ({ 3 | color = 'currentColor', 4 | width = '7px', 5 | height = '10px', 6 | ...props 7 | }) => { 8 | return ( 9 | 16 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /components/icons/map-pin.tsx: -------------------------------------------------------------------------------- 1 | export const MapPin = ({ ...props }) => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /components/icons/minus.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const Minus = ({ 4 | color = 'currentColor', 5 | width = '12px', 6 | height = '12px', 7 | ...props 8 | }) => { 9 | return ( 10 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /components/icons/more-icon.tsx: -------------------------------------------------------------------------------- 1 | export const MoreIcon: React.FC> = (props) => ( 2 | 8 | 9 | 10 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /components/icons/navbar-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const NavbarIcon: React.FC> = (props) => ( 4 | 5 | 6 | 13 | 20 | 27 | 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /components/icons/order-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const OrderIcon = ({ width = '11.321', height = '13' }) => { 3 | return ( 4 | 10 | 11 | 12 | 18 | 24 | 30 | 31 | 32 | 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /components/icons/phone.tsx: -------------------------------------------------------------------------------- 1 | export const PhoneIcon = ({ ...props }) => { 2 | return ( 3 | 8 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /components/icons/product-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const ProductIcon = ({ width = '15.6', height = '13' }) => { 3 | return ( 4 | 10 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /components/icons/save-icon.tsx: -------------------------------------------------------------------------------- 1 | export const SaveIcon: React.FC> = (props) => ( 2 | 15 | ); 16 | -------------------------------------------------------------------------------- /components/icons/search-icon.tsx: -------------------------------------------------------------------------------- 1 | export const SearchIcon: React.FC> = (props) => ( 2 | 15 | ); 16 | -------------------------------------------------------------------------------- /components/icons/shops/cube.tsx: -------------------------------------------------------------------------------- 1 | export const CubeIcon: React.FC> = (props) => { 2 | return ( 3 | 8 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /components/icons/sidebar-category-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export const SidebarCategoryIcon = ({ width = '12.958', height = '13' }) => { 3 | return ( 4 | 10 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /components/icons/sidebar/affiliate.tsx: -------------------------------------------------------------------------------- 1 | export const AffiliateIcon: React.FC> = (props) => ( 2 | 25 | ); 26 | -------------------------------------------------------------------------------- /components/icons/sidebar/apps.tsx: -------------------------------------------------------------------------------- 1 | export const AppsIcon: React.FC> = (props) => ( 2 | 15 | ); 16 | -------------------------------------------------------------------------------- /components/icons/sidebar/categories.tsx: -------------------------------------------------------------------------------- 1 | export const CategoriesIcon: React.FC> = (props) => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/sidebar/coupons.tsx: -------------------------------------------------------------------------------- 1 | export const CouponsIcon: React.FC> = (props) => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/sidebar/image-multiple.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export const ImageMultipleIcon = (props) => ( 4 | 17 | ); 18 | -------------------------------------------------------------------------------- /components/icons/sidebar/order-status.tsx: -------------------------------------------------------------------------------- 1 | export const OrdersStatusIcon: React.FC> = (props) => ( 2 | 12 | 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /components/icons/sidebar/orders.tsx: -------------------------------------------------------------------------------- 1 | export const OrdersIcon: React.FC> = (props) => ( 2 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /components/icons/sidebar/products.tsx: -------------------------------------------------------------------------------- 1 | export const ProductsIcon: React.FC> = (props) => ( 2 | 8 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /components/icons/sidebar/settings.tsx: -------------------------------------------------------------------------------- 1 | export const SettingsIcon: React.FC> = (props) => ( 2 | 9 | 15 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /components/icons/sidebar/shippings.tsx: -------------------------------------------------------------------------------- 1 | export const ShippingsIcon: React.FC> = (props) => ( 2 | 9 | 13 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /components/icons/sidebar/shop.tsx: -------------------------------------------------------------------------------- 1 | export const ShopIcon: React.FC> = (props) => ( 2 | 3 | 4 | 8 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /components/icons/sidebar/staffs.tsx: -------------------------------------------------------------------------------- 1 | export const StaffsIcon: React.FC> = (props) => ( 2 | 15 | ); 16 | -------------------------------------------------------------------------------- /components/icons/sidebar/suppliers.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export const SuppliersIcon: React.FC> = (props) => ( 4 | 10 | 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /components/icons/sidebar/support.tsx: -------------------------------------------------------------------------------- 1 | export const SupportIcon: React.FC> = (props) => ( 2 | 15 | ); 16 | -------------------------------------------------------------------------------- /components/icons/sidebar/tags.tsx: -------------------------------------------------------------------------------- 1 | export const TagIcon: React.FC> = (props) => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/sidebar/taxes.tsx: -------------------------------------------------------------------------------- 1 | export const TaxesIcon: React.FC> = (props) => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/sidebar/users.tsx: -------------------------------------------------------------------------------- 1 | export const UsersIcon: React.FC> = (props) => ( 2 | 9 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /components/icons/sidebar/withdraw.tsx: -------------------------------------------------------------------------------- 1 | export const WithdrawIcon: React.FC> = (props) => ( 2 | 3 | 8 | 13 | 18 | 23 | 24 | ); 25 | -------------------------------------------------------------------------------- /components/icons/social/facebook.tsx: -------------------------------------------------------------------------------- 1 | export const FacebookIcon: React.FC> = (props) => ( 2 | 3 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /components/icons/social/index.tsx: -------------------------------------------------------------------------------- 1 | export { FacebookIcon } from './facebook'; 2 | export { InstagramIcon } from './instagram'; 3 | export { TwitterIcon } from './twitter'; 4 | export { YouTubeIcon } from './youtube'; 5 | -------------------------------------------------------------------------------- /components/icons/social/instagram.tsx: -------------------------------------------------------------------------------- 1 | export const InstagramIcon: React.FC> = (props) => ( 2 | 8 | 13 | 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /components/icons/social/twitter.tsx: -------------------------------------------------------------------------------- 1 | export const TwitterIcon: React.FC> = (props) => ( 2 | 3 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /components/icons/social/youtube.tsx: -------------------------------------------------------------------------------- 1 | export const YouTubeIcon: React.FC> = (props) => ( 2 | 3 | 7 | 8 | ); 9 | -------------------------------------------------------------------------------- /components/icons/trash.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Trash = ({ ...props }) => { 4 | return ( 5 | 11 | 18 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | ); 32 | }; 33 | 34 | export default Trash; 35 | -------------------------------------------------------------------------------- /components/icons/type/index.tsx: -------------------------------------------------------------------------------- 1 | export { FruitsVegetable } from './fruits-vegetable'; 2 | export { FacialCare } from './facial-care'; 3 | export { Handbag } from './handbag-icon'; 4 | export { DressIcon } from './dress-icon'; 5 | export { FurnitureIcon } from './furniture-icon'; 6 | export { BookIcon } from './book-icon'; 7 | export { MedicineIcon } from './medicine-icon'; 8 | export { Restaurant } from './restaurant-icon'; 9 | export { Bakery } from './bakery-icon'; 10 | -------------------------------------------------------------------------------- /components/icons/upload-icon copy.tsx: -------------------------------------------------------------------------------- 1 | export const UploadIcon = ({ 2 | color = 'currentColor', 3 | width = '41px', 4 | height = '30px', 5 | ...rest 6 | }) => { 7 | return ( 8 | 15 | 16 | 22 | 23 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /components/icons/upload-icon.tsx: -------------------------------------------------------------------------------- 1 | export const UploadIcon = ({ 2 | color = 'currentColor', 3 | width = '41px', 4 | height = '30px', 5 | ...rest 6 | }) => { 7 | return ( 8 | 15 | 16 | 22 | 23 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /components/navigation/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as Navbar } from './navbar'; 2 | export { default as Sidebar } from './sidebar'; 3 | export { default as SidebarMini } from './sidebar/sidebar-mini'; 4 | -------------------------------------------------------------------------------- /components/navigation/sidebar/sidebar-mini.tsx: -------------------------------------------------------------------------------- 1 | import Scrollbar from '@components/ui/scrollbar'; 2 | import { siteSettings } from '@settings/site.settings'; 3 | import { useTranslation } from 'next-i18next'; 4 | import React from 'react'; 5 | 6 | import SidebarItem from './sidebar-item-mini'; 7 | 8 | const SidebarMini: React.FC = () => { 9 | const { t } = useTranslation(); 10 | 11 | return ( 12 | 31 | ); 32 | }; 33 | export default SidebarMini; 34 | -------------------------------------------------------------------------------- /components/product/product-validation-schema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | 3 | export const productValidationSchema = yup.object().shape({ 4 | // thumbnail 5 | // gallery 6 | name: yup.string().required('form:error-product-name-required'), 7 | shortDescription: yup 8 | .string() 9 | .test( 10 | 'len', 11 | 'Description Must be less than 160 characters', 12 | (val) => val.length < 160 13 | ) 14 | .required('form:error-short-description-required'), 15 | description: yup.string().required('form:error-product-description-required'), 16 | // salePrice: yup 17 | // .number() 18 | // .typeError('form:error-amount-must-number') 19 | // .positive('form:error-price-must-positive') 20 | // .required('form:error-sale-price-required'), 21 | // comparePrice: yup 22 | // .number() 23 | // .typeError('form:error-amount-must-number') 24 | // .transform((value) => (isNaN(value) ? null : value)), 25 | // quantity: yup 26 | // .number() 27 | // .typeError('form:error-amount-must-number') 28 | // .required('form:error-quantity-required'), 29 | categories: yup.array().min(1, 'Category Required') 30 | }); 31 | -------------------------------------------------------------------------------- /components/settings/settings-validation-schema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | export const settingsValidationSchema = yup.object().shape({ 3 | currency: yup.object().nullable().required('form:error-currency-required'), 4 | minimumOrderAmount: yup 5 | .number() 6 | .transform((value) => (isNaN(value) ? undefined : value)) 7 | .moreThan(-1, 'form:error-sale-price-must-positive'), 8 | deliveryTime: yup 9 | .array() 10 | .min(1, 'add-at-least-one-delivery-time') 11 | .of( 12 | yup.object().shape({ 13 | title: yup.string().required('form:error-title-required') 14 | }) 15 | ) 16 | }); 17 | -------------------------------------------------------------------------------- /components/staff/staff-validation-schema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup'; 2 | 3 | export const staffValidationSchema = yup.object().shape({ 4 | firstName: yup.string().required('form:error-last-name-required'), 5 | lastName: yup.string().required('form:error-first-name-required'), 6 | email: yup 7 | .string() 8 | .email('form:error-email-format') 9 | .required('form:error-email-required'), 10 | confirmPassword: yup 11 | .string() 12 | .oneOf([yup.ref('password'), null], 'form:error-match-passwords') 13 | .required('form:error-confirm-password'), 14 | password: yup.string().required('form:error-password-required') 15 | }); 16 | -------------------------------------------------------------------------------- /components/ui/activeLink.tsx: -------------------------------------------------------------------------------- 1 | import NextLink, { LinkProps as NextLinkProps } from 'next/link'; 2 | import { useRouter } from 'next/router'; 3 | import React, { useMemo } from 'react'; 4 | 5 | type Props = { 6 | activeClassName: string; 7 | includes: string; 8 | className: string; 9 | }; 10 | 11 | const ActiveLink: React.FC = ({ 12 | href, 13 | children, 14 | activeClassName, 15 | className, 16 | includes, 17 | ...props 18 | }) => { 19 | const { asPath } = useRouter(); 20 | 21 | const A = useMemo(() => asPath?.split('/'), [asPath]); 22 | const B = useMemo(() => includes?.split('/'), [includes]); 23 | 24 | const class_name = 25 | asPath === href || 26 | asPath === props.as || 27 | A[A?.length - 1] === B[B?.length - 1] 28 | ? `${className} ${activeClassName}`.trim() 29 | : className; 30 | 31 | return ( 32 | 33 | {children} 34 | 35 | ); 36 | }; 37 | 38 | export default ActiveLink; 39 | -------------------------------------------------------------------------------- /components/ui/badge/badge.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'classnames'; 2 | import { useTranslation } from 'next-i18next'; 3 | import React from 'react'; 4 | 5 | type BadgeProps = { 6 | className?: string; 7 | color?: string; 8 | textColor?: string; 9 | text?: string; 10 | textKey?: string; 11 | }; 12 | 13 | const Badge: React.FC = (props) => { 14 | const { t } = useTranslation(); 15 | const { 16 | className, 17 | color: colorOverride, 18 | textColor: textColorOverride, 19 | text, 20 | textKey 21 | } = props; 22 | 23 | const classes = { 24 | root: 'px-3 py-1 rounded-sm text-xs whitespace-nowrap shadow-sm', 25 | default: 'bg-accent', 26 | text: 'text-light' 27 | }; 28 | 29 | return ( 30 | 42 | {textKey ? t(textKey) : text} 43 | 44 | ); 45 | }; 46 | 47 | export default Badge; 48 | -------------------------------------------------------------------------------- /components/ui/chart.tsx: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic'; 2 | 3 | const Charts = dynamic(() => import('react-apexcharts'), { ssr: false }); 4 | 5 | const Chart = ({ ...props }) => { 6 | return ; 7 | }; 8 | 9 | export default Chart; 10 | -------------------------------------------------------------------------------- /components/ui/checkbox/checkbox.module.css: -------------------------------------------------------------------------------- 1 | .checkbox { 2 | position: absolute; 3 | opacity: 0; 4 | } 5 | 6 | .checkbox + label { 7 | position: relative; 8 | cursor: pointer; 9 | padding: 0; 10 | display: inline-flex; 11 | align-items: center; 12 | } 13 | 14 | .checkbox + label:before { 15 | content: ''; 16 | margin-right: 10px; 17 | display: inline-flex; 18 | width: 18px; 19 | height: 18px; 20 | border-radius: 3px; 21 | background-color: #ffffff; 22 | border: 1px solid rgb(var(--color-gray-300)); 23 | } 24 | 25 | .checkbox:focus + label:before { 26 | border-color: rgb(var(--color-accent)); 27 | } 28 | 29 | .checkbox:checked + label:before { 30 | background-color: rgb(var(--color-accent)); 31 | border-color: rgb(var(--color-accent)); 32 | } 33 | 34 | .checkbox:disabled + label { 35 | color: rgb(var(--text-base)); 36 | cursor: auto; 37 | } 38 | 39 | .checkbox:disabled + label:before { 40 | box-shadow: none; 41 | background: rgb(var(--color-gray-300)); 42 | } 43 | 44 | .checkbox:checked + label:after { 45 | content: ''; 46 | position: absolute; 47 | left: 4px; 48 | top: 9px; 49 | background: #ffffff; 50 | width: 2px; 51 | height: 2px; 52 | box-shadow: 2px 0 0 #ffffff, 4px 0 0 #ffffff, 4px -2px 0 #ffffff, 53 | 4px -4px 0 #ffffff, 4px -6px 0 #ffffff, 4px -8px 0 #ffffff; 54 | transform: rotate(45deg); 55 | } 56 | -------------------------------------------------------------------------------- /components/ui/checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { InputHTMLAttributes } from 'react'; 2 | 3 | import styles from './checkbox.module.css'; 4 | 5 | export interface Props extends InputHTMLAttributes { 6 | className?: string; 7 | label?: string; 8 | name: string; 9 | error?: string; 10 | inputClassName?: string; 11 | } 12 | 13 | const Checkbox = React.forwardRef( 14 | ( 15 | { className, inputClassName, style, label, id, name, error, ...rest }, 16 | ref 17 | ) => { 18 | return ( 19 |
20 |
21 | 29 | 30 | 33 |
34 | 35 | {error &&

{error}

} 36 |
37 | ); 38 | } 39 | ); 40 | 41 | Checkbox.displayName = 'Checkbox'; 42 | 43 | export default Checkbox; 44 | -------------------------------------------------------------------------------- /components/ui/color-picker/display-color-code.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useWatch } from 'react-hook-form'; 3 | 4 | const DisplayColorCode = ({ control }: any) => { 5 | const color = useWatch({ 6 | control, 7 | name: 'color', 8 | defaultValue: '#9cd864' // default value before the render 9 | }); 10 | return ( 11 | <> 12 | {color !== null && ( 13 | 14 | {color} 15 | 16 | )} 17 | 18 | ); 19 | }; 20 | 21 | export default DisplayColorCode; 22 | -------------------------------------------------------------------------------- /components/ui/date-picker.tsx: -------------------------------------------------------------------------------- 1 | import 'react-datepicker/dist/react-datepicker.css'; 2 | export { default as DatePicker } from 'react-datepicker'; 3 | -------------------------------------------------------------------------------- /components/ui/description.tsx: -------------------------------------------------------------------------------- 1 | type Props = { 2 | className?: string; 3 | title?: string; 4 | details?: string | JSX.Element; 5 | [key: string]: unknown; 6 | }; 7 | 8 | const Description: React.FC = ({ 9 | title, 10 | details, 11 | className, 12 | ...props 13 | }) => { 14 | return ( 15 |
16 | {title && ( 17 |

{title}

18 | )} 19 | {details &&

{details}

} 20 |
21 | ); 22 | }; 23 | 24 | export default Description; 25 | -------------------------------------------------------------------------------- /components/ui/editor/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import { Controller } from 'react-hook-form'; 3 | 4 | import EditorComponent from './editor'; 5 | 6 | interface EditorInputProps { 7 | control: any; 8 | className?: string; 9 | name: string; 10 | [key: string]: unknown; 11 | } 12 | 13 | const Editor = ({ className, control, name, ...rest }: EditorInputProps) => { 14 | return ( 15 | ( 20 | 21 | )} 22 | /> 23 | ); 24 | }; 25 | 26 | export default memo(Editor); 27 | -------------------------------------------------------------------------------- /components/ui/error-message.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'next-i18next'; 2 | interface Props { 3 | message?: string | undefined; 4 | } 5 | 6 | export const Error = ({ message }: Props) => { 7 | const { t } = useTranslation('common'); 8 | return

{t(message!)}

; 9 | }; 10 | 11 | const ErrorMessage = ({ message }: Props) => { 12 | const { t } = useTranslation('common'); 13 | return ( 14 |

15 | {t(message!)} 16 |

17 | ); 18 | }; 19 | 20 | export default ErrorMessage; 21 | -------------------------------------------------------------------------------- /components/ui/file-input.tsx: -------------------------------------------------------------------------------- 1 | import Uploader from '@components/common/uploader'; 2 | import { Controller } from 'react-hook-form'; 3 | 4 | interface FileInputProps { 5 | control: any; 6 | name: string; 7 | multiple?: boolean; 8 | } 9 | 10 | const FileInput = ({ control, name, multiple = true }: FileInputProps) => { 11 | return ( 12 | ( 18 | 19 | )} 20 | /> 21 | ); 22 | }; 23 | 24 | export default FileInput; 25 | -------------------------------------------------------------------------------- /components/ui/form-validation-error.tsx: -------------------------------------------------------------------------------- 1 | interface Props { 2 | message: string | undefined; 3 | } 4 | 5 | const ValidationError = ({ message }: Props) => { 6 | return

{message}

; 7 | }; 8 | 9 | export default ValidationError; 10 | -------------------------------------------------------------------------------- /components/ui/form/form.tsx: -------------------------------------------------------------------------------- 1 | import { SubmitHandler, useForm, UseFormReturn } from 'react-hook-form'; 2 | 3 | type FormProps = { 4 | onSubmit: SubmitHandler; 5 | children: (methods: UseFormReturn) => React.ReactNode; 6 | }; 7 | 8 | export const Form = < 9 | TFormValues extends Record = Record 10 | >({ 11 | onSubmit, 12 | children 13 | }: FormProps) => { 14 | const methods = useForm(); 15 | return ( 16 |
{children(methods)}
17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /components/ui/import-csv.tsx: -------------------------------------------------------------------------------- 1 | import { UploadIcon } from '@components/icons/upload-icon'; 2 | import { useDropzone } from 'react-dropzone'; 3 | 4 | export default function ImportCsv({ onDrop, loading, title }: any) { 5 | const { getRootProps, getInputProps } = useDropzone({ 6 | accept: '.csv', 7 | multiple: false, 8 | onDrop 9 | }); 10 | 11 | return ( 12 |
13 |
19 | 20 | {loading && ( 21 | 27 | )} 28 | {!loading && } 29 |

30 | {title} 31 |

32 |
33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import cn from 'classnames'; 2 | import { LabelHTMLAttributes } from 'react'; 3 | 4 | export interface Props extends LabelHTMLAttributes { 5 | className?: string; 6 | } 7 | 8 | const Label: React.FC = ({ className, ...rest }) => { 9 | return ( 10 |