├── server ├── .nvmrc ├── .dockerignore ├── Procfile ├── .jshintrc ├── LICENSE ├── .eslintignore ├── Dockerfile ├── test │ ├── app │ │ ├── controller │ │ │ ├── payloads.js │ │ │ └── routes.test.js │ │ └── app.test.js │ └── mock-routes │ │ └── routes.js ├── setup │ ├── roles.json │ ├── products.js │ └── migrate.js ├── src │ ├── modules │ │ ├── customer │ │ │ ├── index.js │ │ │ ├── request.js │ │ │ └── service.js │ │ ├── resource │ │ │ ├── request.js │ │ │ ├── service.js │ │ │ ├── index.js │ │ │ └── model.js │ │ ├── role │ │ │ ├── request.js │ │ │ ├── index.js │ │ │ ├── service.js │ │ │ └── controller.js │ │ ├── blog │ │ │ └── index.js │ │ ├── product │ │ │ └── index.js │ │ ├── payment │ │ │ ├── index.js │ │ │ └── model.js │ │ ├── permission │ │ │ ├── index.js │ │ │ ├── request.js │ │ │ ├── service.js │ │ │ ├── model.js │ │ │ └── controller.js │ │ ├── salesOrder │ │ │ ├── index.js │ │ │ ├── productSchema.js │ │ │ └── controller.js │ │ ├── user │ │ │ └── index.js │ │ └── index.js │ ├── core │ │ ├── event-manager.js │ │ ├── index.js │ │ ├── logger.js │ │ └── mongo.js │ ├── email │ │ └── sendgrid.js │ └── common │ │ ├── utils.js │ │ └── errors.js ├── db.yml ├── .env.sample └── docker-compose.yml ├── server-nest ├── files │ └── invalid-customers.txt ├── .prettierrc ├── src │ ├── modules │ │ ├── auth │ │ │ ├── constants.ts │ │ │ ├── role.enum.ts │ │ │ ├── jwt-payload.interface.ts │ │ │ ├── guards │ │ │ │ ├── local-auth.guard.ts │ │ │ │ ├── jwt-auth.guard.ts │ │ │ │ └── role.guard.ts │ │ │ ├── roles.decorator.ts │ │ │ ├── local.strategy.ts │ │ │ ├── jwt.strategy.ts │ │ │ └── auth.module.ts │ │ ├── blog │ │ │ ├── dto │ │ │ │ ├── updateBlog.dto.ts │ │ │ │ └── createBlog.dto.ts │ │ │ └── blog.module.ts │ │ ├── role │ │ │ ├── dto │ │ │ │ ├── updateRole.dto.ts │ │ │ │ └── createRole.dto.ts │ │ │ └── role.module.ts │ │ ├── user │ │ │ ├── dto │ │ │ │ ├── updateUser.dto.ts │ │ │ │ ├── loginUsers.dto.ts │ │ │ │ └── getUsers.dto.ts │ │ │ ├── user.module.ts │ │ │ └── user.service.ts │ │ ├── product │ │ │ ├── dto │ │ │ │ ├── updateProduct.dto.ts │ │ │ │ └── createProduct.dto.ts │ │ │ └── product.module.ts │ │ ├── location │ │ │ ├── dto │ │ │ │ ├── updateLocation.dto.ts │ │ │ │ ├── updateLocationRelationship.dto.ts │ │ │ │ ├── createLocationRelationship.dto.ts │ │ │ │ └── createLocation.dto.ts │ │ │ ├── location.module.ts │ │ │ ├── entity │ │ │ │ ├── locationRelationship.entity.ts │ │ │ │ └── location.entity.ts │ │ │ └── location.controller.ts │ │ ├── resource │ │ │ ├── dto │ │ │ │ ├── updateResource.dto.ts │ │ │ │ └── createResource.dto.ts │ │ │ ├── resource.module.ts │ │ │ └── entity │ │ │ │ └── resource.entity.ts │ │ ├── permission │ │ │ ├── dto │ │ │ │ ├── updatePermission.dto.ts │ │ │ │ └── createPermission.dto.ts │ │ │ └── permission.module.ts │ │ └── customer │ │ │ ├── dto │ │ │ ├── updateCustomer.dto.ts │ │ │ └── createCustomer.dto.ts │ │ │ ├── customer.module.ts │ │ │ └── entity │ │ │ └── customer.entity.ts │ ├── dto │ │ ├── response.dto.ts │ │ └── getQueryDto.ts │ ├── app.service.ts │ ├── app.controller.ts │ ├── config │ │ └── config.module.ts │ └── main.ts ├── tsconfig.build.json ├── nest-cli.json ├── test │ ├── jest-e2e.json │ └── app.e2e-spec.ts ├── .env.example ├── tsconfig.json └── .eslintrc.js ├── client ├── public │ ├── _redirects │ ├── robots.txt │ ├── logo │ │ └── logo_full.jpg │ ├── favicon │ │ ├── favicon.ico │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── apple-touch-icon.png │ │ ├── android-chrome-192x192.png │ │ └── android-chrome-512x512.png │ ├── fonts │ │ ├── Roboto-Bold.ttf │ │ ├── CircularStd-Bold.otf │ │ ├── CircularStd-Book.otf │ │ ├── Roboto-Regular.ttf │ │ ├── CircularStd-Medium.otf │ │ └── index.css │ ├── icons │ │ ├── ic_user.svg │ │ ├── ic_mail.svg │ │ ├── ic_github.svg │ │ ├── ic_kanban.svg │ │ ├── ic_dashboard.svg │ │ ├── ic_chat.svg │ │ └── ic_booking.svg │ └── manifest.json ├── .prettierignore ├── src │ ├── sections │ │ ├── auth │ │ │ ├── login │ │ │ │ └── index.js │ │ │ ├── register │ │ │ │ └── index.js │ │ │ ├── verify-code │ │ │ │ └── index.js │ │ │ ├── reset-password │ │ │ │ └── index.js │ │ │ └── AuthFirebaseSocial.js │ │ ├── @dashboard │ │ │ ├── user │ │ │ │ ├── cards │ │ │ │ │ └── index.js │ │ │ │ ├── list │ │ │ │ │ └── index.js │ │ │ │ ├── account │ │ │ │ │ └── index.js │ │ │ │ └── profile │ │ │ │ │ └── index.js │ │ │ ├── e-commerce │ │ │ │ ├── invoice │ │ │ │ │ └── index.js │ │ │ │ ├── product-list │ │ │ │ │ └── index.js │ │ │ │ ├── shop │ │ │ │ │ ├── index.js │ │ │ │ │ └── ShopProductList.js │ │ │ │ ├── product-details │ │ │ │ │ └── index.js │ │ │ │ └── checkout │ │ │ │ │ └── index.js │ │ │ ├── kanban │ │ │ │ └── index.js │ │ │ ├── calendar │ │ │ │ └── index.js │ │ │ ├── general │ │ │ │ ├── banking │ │ │ │ │ └── index.js │ │ │ │ ├── app │ │ │ │ │ └── index.js │ │ │ │ ├── booking │ │ │ │ │ └── index.js │ │ │ │ ├── e-commerce │ │ │ │ │ └── index.js │ │ │ │ └── analytics │ │ │ │ │ └── index.js │ │ │ ├── mail │ │ │ │ └── index.js │ │ │ ├── blog │ │ │ │ ├── index.js │ │ │ │ ├── BlogPostsSort.js │ │ │ │ └── BlogPostRecent.js │ │ │ └── chat │ │ │ │ └── index.js │ │ ├── pricing │ │ │ └── index.js │ │ ├── contact │ │ │ └── index.js │ │ ├── faqs │ │ │ ├── index.js │ │ │ └── FaqsList.js │ │ ├── payment │ │ │ ├── index.js │ │ │ └── PaymentBillingAddress.js │ │ ├── about │ │ │ └── index.js │ │ ├── home │ │ │ └── index.js │ │ └── map │ │ │ ├── index.js │ │ │ └── dynamic-styling │ │ │ └── index.js │ ├── components │ │ ├── animate │ │ │ ├── features.js │ │ │ ├── variants │ │ │ │ ├── actions.js │ │ │ │ ├── path.js │ │ │ │ ├── index.js │ │ │ │ ├── container.js │ │ │ │ ├── transition.js │ │ │ │ └── rotate.js │ │ │ ├── MotionLazyContainer.js │ │ │ ├── index.js │ │ │ ├── TextAnimate.js │ │ │ └── MotionContainer.js │ │ ├── chart │ │ │ └── index.js │ │ ├── upload │ │ │ ├── index.js │ │ │ └── BlockContent.js │ │ ├── carousel │ │ │ └── index.js │ │ ├── color-utils │ │ │ └── index.js │ │ ├── mega-menu │ │ │ ├── index.js │ │ │ └── MenuHotProducts.js │ │ ├── ScrollToTop.js │ │ ├── map │ │ │ ├── index.js │ │ │ ├── MapControlGeolocate.js │ │ │ ├── MapControlFullscreen.js │ │ │ ├── MapControlNavigation.js │ │ │ ├── MapControlScale.js │ │ │ └── MapControlMarker.js │ │ ├── hook-form │ │ │ ├── index.js │ │ │ ├── FormProvider.js │ │ │ ├── RHFSwitch.js │ │ │ ├── RHFTextField.js │ │ │ ├── RHFSelect.js │ │ │ └── RHFEditor.js │ │ ├── nav-section │ │ │ ├── index.js │ │ │ └── horizontal │ │ │ │ └── index.js │ │ ├── skeleton │ │ │ ├── SkeletonMailSidebarItem.js │ │ │ ├── SkeletonMap.js │ │ │ ├── index.js │ │ │ ├── SkeletonPostItem.js │ │ │ ├── SkeletonConversationItem.js │ │ │ ├── SkeletonPost.js │ │ │ ├── SkeletonProduct.js │ │ │ ├── SkeletonProductItem.js │ │ │ └── SkeletonKanbanColumn.js │ │ ├── Iconify.js │ │ ├── MyAvatar.js │ │ ├── ThemeLocalization.js │ │ ├── SvgIconStyle.js │ │ ├── Page.js │ │ ├── TextIconLabel.js │ │ ├── SearchNotFound.js │ │ ├── RtlLayout.js │ │ ├── InputStyle.js │ │ ├── Avatar.js │ │ └── ThemeColorPresets.js │ ├── theme │ │ ├── overrides │ │ │ ├── Link.js │ │ │ ├── Stepper.js │ │ │ ├── Select.js │ │ │ ├── Badge.js │ │ │ ├── Breadcrumbs.js │ │ │ ├── Popover.js │ │ │ ├── Skeleton.js │ │ │ ├── Typography.js │ │ │ ├── Radio.js │ │ │ ├── Timeline.js │ │ │ ├── Menu.js │ │ │ ├── SvgIcon.js │ │ │ ├── Tooltip.js │ │ │ ├── Paper.js │ │ │ ├── LoadingButton.js │ │ │ ├── Autocomplete.js │ │ │ ├── ControlLabel.js │ │ │ ├── Progress.js │ │ │ ├── Slider.js │ │ │ ├── Avatar.js │ │ │ ├── TreeView.js │ │ │ ├── Drawer.js │ │ │ ├── Rating.js │ │ │ ├── List.js │ │ │ ├── Backdrop.js │ │ │ ├── Card.js │ │ │ ├── Switch.js │ │ │ ├── Fab.js │ │ │ ├── Accordion.js │ │ │ ├── Checkbox.js │ │ │ ├── Pagination.js │ │ │ └── CssBaseline.js │ │ └── breakpoints.js │ ├── hooks │ │ ├── useSettings.js │ │ ├── useCollapseDrawer.js │ │ ├── useIsMountedRef.js │ │ ├── useAuth.js │ │ ├── useOffSetTop.js │ │ ├── useResponsive.js │ │ └── useLocalStorage.js │ ├── utils │ │ ├── uuidv4.js │ │ ├── highlight.js │ │ ├── axios.js │ │ ├── formatNumber.js │ │ ├── formatTime.js │ │ ├── getColorName.js │ │ └── createAvatar.js │ ├── reportWebVitals.js │ ├── _mock │ │ ├── funcs.js │ │ ├── index.js │ │ ├── boolean.js │ │ ├── phoneNumber.js │ │ ├── role.js │ │ ├── number.js │ │ └── company.js │ ├── helpers │ │ └── checkPermission.js │ ├── guards │ │ ├── GuestGuard.js │ │ ├── RoleGuard.js │ │ ├── RoleBasedGuard.js │ │ └── AuthGuard.js │ ├── locales │ │ ├── en.json │ │ ├── de.json │ │ ├── fr.json │ │ └── i18n.js │ ├── layouts │ │ ├── LogoOnlyLayout.js │ │ └── dashboard │ │ │ └── navbar │ │ │ └── NavbarDocs.js │ ├── redux │ │ ├── store.js │ │ └── rootReducer.js │ ├── pages │ │ ├── About.js │ │ ├── dashboard │ │ │ └── BlogNewPost.js │ │ ├── ComponentsOverview.js │ │ └── Contact.js │ └── assets │ │ └── index.js ├── .prettierrc ├── .eslintignore ├── jsconfig.json ├── Dockerfile └── .env.sample ├── docs └── images │ ├── appserver-lsla.png │ ├── login-screen.png │ ├── product-shop.png │ ├── product-list-search.png │ ├── appserver-db-seed-users.png │ └── appserver-db-seed-products.png ├── .dockerrc ├── .idea └── .gitignore ├── .github └── FUNDING.yml └── package.json /server/.nvmrc: -------------------------------------------------------------------------------- 1 | 16.14.2 -------------------------------------------------------------------------------- /server/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /server/Procfile: -------------------------------------------------------------------------------- 1 | web: npm start -------------------------------------------------------------------------------- /server-nest/files/invalid-customers.txt: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /client/public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /server/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 9 3 | } 4 | -------------------------------------------------------------------------------- /server/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MD. Shakil Hasan -------------------------------------------------------------------------------- /server/.eslintignore: -------------------------------------------------------------------------------- 1 | .meteor 2 | .storybook 3 | node_modules 4 | packages 5 | -------------------------------------------------------------------------------- /server-nest/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /client/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | package-lock.json 4 | public 5 | 6 | -------------------------------------------------------------------------------- /client/src/sections/auth/login/index.js: -------------------------------------------------------------------------------- 1 | export { default as LoginForm } from './LoginForm'; 2 | -------------------------------------------------------------------------------- /client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/user/cards/index.js: -------------------------------------------------------------------------------- 1 | export { default as UserCard } from './UserCard'; 2 | -------------------------------------------------------------------------------- /client/src/sections/auth/register/index.js: -------------------------------------------------------------------------------- 1 | export { default as RegisterForm } from './RegisterForm'; 2 | -------------------------------------------------------------------------------- /client/src/sections/pricing/index.js: -------------------------------------------------------------------------------- 1 | export { default as PricingPlanCard } from './PricingPlanCard'; 2 | -------------------------------------------------------------------------------- /client/src/sections/auth/verify-code/index.js: -------------------------------------------------------------------------------- 1 | export { default as VerifyCodeForm } from './VerifyCodeForm'; 2 | -------------------------------------------------------------------------------- /docs/images/appserver-lsla.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/docs/images/appserver-lsla.png -------------------------------------------------------------------------------- /docs/images/login-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/docs/images/login-screen.png -------------------------------------------------------------------------------- /docs/images/product-shop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/docs/images/product-shop.png -------------------------------------------------------------------------------- /server-nest/src/modules/auth/constants.ts: -------------------------------------------------------------------------------- 1 | export const jwtConstants = { 2 | secret: 'secretKey', 3 | }; 4 | -------------------------------------------------------------------------------- /client/public/logo/logo_full.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/logo/logo_full.jpg -------------------------------------------------------------------------------- /client/src/components/animate/features.js: -------------------------------------------------------------------------------- 1 | import { domMax } from 'framer-motion'; 2 | 3 | export default domMax; 4 | -------------------------------------------------------------------------------- /.dockerrc: -------------------------------------------------------------------------------- 1 | { 2 | "containers": [ 3 | "0743dbe10ef8", 4 | "79a61bc6fd04", 5 | "24250e89ec68" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /client/public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/favicon/favicon.ico -------------------------------------------------------------------------------- /client/public/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /client/src/sections/auth/reset-password/index.js: -------------------------------------------------------------------------------- 1 | export { default as ResetPasswordForm } from './ResetPasswordForm'; 2 | -------------------------------------------------------------------------------- /docs/images/product-list-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/docs/images/product-list-search.png -------------------------------------------------------------------------------- /client/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "tabWidth": 2 6 | } 7 | -------------------------------------------------------------------------------- /client/public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /client/public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /client/public/fonts/CircularStd-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/fonts/CircularStd-Bold.otf -------------------------------------------------------------------------------- /client/public/fonts/CircularStd-Book.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/fonts/CircularStd-Book.otf -------------------------------------------------------------------------------- /client/public/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /docs/images/appserver-db-seed-users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/docs/images/appserver-db-seed-users.png -------------------------------------------------------------------------------- /client/public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /client/public/fonts/CircularStd-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/fonts/CircularStd-Medium.otf -------------------------------------------------------------------------------- /docs/images/appserver-db-seed-products.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/docs/images/appserver-db-seed-products.png -------------------------------------------------------------------------------- /server-nest/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /client/public/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /client/public/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shakilhasan/sabil/HEAD/client/public/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /server-nest/src/modules/auth/role.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RoleEnum { 2 | User = 'user', 3 | Admin = 'admin', 4 | SuperAdmin = 'Super Admin', 5 | } 6 | -------------------------------------------------------------------------------- /client/src/components/chart/index.js: -------------------------------------------------------------------------------- 1 | export { default as ChartStyle } from './ChartStyle'; 2 | export { default as BaseOptionChart } from './BaseOptionChart'; 3 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/jwt-payload.interface.ts: -------------------------------------------------------------------------------- 1 | export interface JwtPayload { 2 | username: string; 3 | password: string; 4 | roleAlias?: string; 5 | } 6 | -------------------------------------------------------------------------------- /client/.eslintignore: -------------------------------------------------------------------------------- 1 | // .eslintignore 2 | build/* 3 | public/* 4 | src/service-worker.js 5 | src/serviceWorkerRegistration.js 6 | src/setupTests.js 7 | src/reportWebVitals.js 8 | -------------------------------------------------------------------------------- /server-nest/src/dto/response.dto.ts: -------------------------------------------------------------------------------- 1 | export class ResponseDto { 2 | ok: boolean; 3 | data?: any; 4 | message?: string; 5 | error?: any; 6 | nTotal?: number; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/e-commerce/invoice/index.js: -------------------------------------------------------------------------------- 1 | export { default as InvoicePDF } from './InvoicePDF'; 2 | export { default as InvoiceToolbar } from './InvoiceToolbar'; 3 | -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts 2 | WORKDIR /usr/src/app 3 | COPY package*.json ./ 4 | ENV NODE_ENV=production 5 | RUN npm ci 6 | COPY . . 7 | EXPOSE 8008 8 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /server/test/app/controller/payloads.js: -------------------------------------------------------------------------------- 1 | const missingNamePayload = { 2 | name: 'shakil', 3 | phone: '+8801981998640', 4 | } 5 | 6 | module.exports = { 7 | missingNamePayload, 8 | } -------------------------------------------------------------------------------- /server-nest/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/src/sections/contact/index.js: -------------------------------------------------------------------------------- 1 | export { default as ContactMap } from './ContactMap'; 2 | export { default as ContactHero } from './ContactHero'; 3 | export { default as ContactForm } from './ContactForm'; 4 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /server-nest/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "deleteOutDir": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/src/components/animate/variants/actions.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const varHover = (scale) => ({ 4 | hover: { 5 | scale: scale || 1.1 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /client/src/components/upload/index.js: -------------------------------------------------------------------------------- 1 | export { default as UploadAvatar } from './UploadAvatar'; 2 | export { default as UploadMultiFile } from './UploadMultiFile'; 3 | export { default as UploadSingleFile } from './UploadSingleFile'; 4 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/kanban/index.js: -------------------------------------------------------------------------------- 1 | export { default as KanbanCard } from './KanbanTaskCard'; 2 | export { default as KanbanColumn } from './KanbanColumn'; 3 | export { default as KanbanColumnAdd } from './KanbanColumnAdd'; 4 | -------------------------------------------------------------------------------- /server-nest/src/modules/blog/dto/updateBlog.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateBlogDto } from './createBlog.dto'; 3 | 4 | export class UpdateBlogDto extends PartialType(CreateBlogDto) {} 5 | -------------------------------------------------------------------------------- /server-nest/src/modules/role/dto/updateRole.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateRoleDto } from './createRole.dto'; 3 | 4 | export class UpdateRoleDto extends PartialType(CreateRoleDto) {} 5 | -------------------------------------------------------------------------------- /client/src/components/carousel/index.js: -------------------------------------------------------------------------------- 1 | export { default as CarouselDots } from './CarouselDots'; 2 | export { default as CarouselArrows } from './CarouselArrows'; 3 | export { default as CarouselArrowIndex } from './CarouselArrowIndex'; 4 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/calendar/index.js: -------------------------------------------------------------------------------- 1 | export { default as CalendarForm } from './CalendarForm'; 2 | export { default as CalendarStyle } from './CalendarStyle'; 3 | export { default as CalendarToolbar } from './CalendarToolbar'; 4 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/user/list/index.js: -------------------------------------------------------------------------------- 1 | export { default as UserListHead } from './UserListHead'; 2 | export { default as UserListToolbar } from './UserListToolbar'; 3 | export { default as UserMoreMenu } from './UserMoreMenu'; 4 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/guards/local-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { AuthGuard } from '@nestjs/passport'; 3 | 4 | @Injectable() 5 | export class LocalAuthGuard extends AuthGuard('local') {} 6 | -------------------------------------------------------------------------------- /server-nest/src/modules/user/dto/updateUser.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | 3 | import { CreateUserDto } from './createUser.dto'; 4 | 5 | export class UpdateUserDto extends PartialType(CreateUserDto) {} 6 | -------------------------------------------------------------------------------- /client/src/components/color-utils/index.js: -------------------------------------------------------------------------------- 1 | export { default as ColorPreview } from './ColorPreview'; 2 | export { default as ColorManyPicker } from './ColorManyPicker'; 3 | export { default as ColorSinglePicker } from './ColorSinglePicker'; 4 | -------------------------------------------------------------------------------- /server-nest/src/modules/product/dto/updateProduct.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateProductDto } from './createProduct.dto'; 3 | 4 | export class UpdateProductDto extends PartialType(CreateProductDto) {} 5 | -------------------------------------------------------------------------------- /client/src/sections/faqs/index.js: -------------------------------------------------------------------------------- 1 | export { default as FaqsHero } from './FaqsHero'; 2 | export { default as FaqsList } from './FaqsList'; 3 | export { default as FaqsForm } from './FaqsForm'; 4 | export { default as FaqsCategory } from './FaqsCategory'; 5 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/dto/updateLocation.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateLocationDto } from './createLocation.dto'; 3 | 4 | export class UpdateLocationDto extends PartialType(CreateLocationDto) {} 5 | -------------------------------------------------------------------------------- /server-nest/src/modules/resource/dto/updateResource.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateResourceDto } from './createResource.dto'; 3 | 4 | export class UpdateResourceDto extends PartialType(CreateResourceDto) {} 5 | -------------------------------------------------------------------------------- /server-nest/src/modules/user/dto/loginUsers.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class LoginUsersDto { 4 | @IsString() 5 | readonly username: string; 6 | 7 | @IsString() 8 | readonly password: string; 9 | } 10 | -------------------------------------------------------------------------------- /server-nest/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/roles.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | import { RoleEnum } from './role.enum'; 3 | 4 | export const ROLES_KEY = 'roles'; 5 | export const Roles = (...roles: RoleEnum[]) => SetMetadata(ROLES_KEY, roles); 6 | -------------------------------------------------------------------------------- /server/test/app/app.test.js: -------------------------------------------------------------------------------- 1 | const app = require('../../src/app') 2 | 3 | test('App Environment', () => { 4 | expect(app.settings.env).toEqual('test') 5 | }) 6 | 7 | test('App Base Path', () => { 8 | expect(app.mountpath).toEqual('/') 9 | }) 10 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/e-commerce/product-list/index.js: -------------------------------------------------------------------------------- 1 | export { default as ProductListHead } from './ProductListHead'; 2 | export { default as ProductListToolbar } from './ProductListToolbar'; 3 | export { default as ProductMoreMenu } from './ProductMoreMenu'; 4 | -------------------------------------------------------------------------------- /server-nest/src/modules/permission/dto/updatePermission.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreatePermissionDto } from './createPermission.dto'; 3 | 4 | export class UpdatePermissionDto extends PartialType(CreatePermissionDto) {} 5 | -------------------------------------------------------------------------------- /client/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "baseUrl": "." 6 | }, 7 | "include": [ 8 | "src/**/*" 9 | ], 10 | "exclude": [ 11 | "node_modules", 12 | "**/node_modules/*" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /server/setup/roles.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "superadmin", 4 | "alias": "Super Admin" 5 | }, 6 | { 7 | "name": "admin", 8 | "alias": "Admin" 9 | }, 10 | { 11 | "name": "user", 12 | "alias": "User" 13 | } 14 | ] -------------------------------------------------------------------------------- /client/src/theme/overrides/Link.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Link() { 4 | return { 5 | MuiLink: { 6 | defaultProps: { 7 | underline: 'hover', 8 | }, 9 | }, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /client/src/theme/breakpoints.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | const breakpoints = { 4 | values: { 5 | xs: 0, 6 | sm: 600, 7 | md: 900, 8 | lg: 1200, 9 | xl: 1536 10 | } 11 | }; 12 | 13 | export default breakpoints; 14 | -------------------------------------------------------------------------------- /client/src/hooks/useSettings.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { SettingsContext } from '../contexts/SettingsContext'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | const useSettings = () => useContext(SettingsContext); 7 | 8 | export default useSettings; 9 | -------------------------------------------------------------------------------- /client/src/sections/payment/index.js: -------------------------------------------------------------------------------- 1 | export { default as PaymentBillingAddress } from './PaymentBillingAddress'; 2 | export { default as PaymentMethods } from './PaymentMethods'; 3 | export { default as PaymentNewCardForm } from './PaymentNewCardForm'; 4 | export { default as PaymentSummary } from './PaymentSummary'; 5 | -------------------------------------------------------------------------------- /server/src/modules/customer/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { authenticateRequest } = require("../../common/middlewares"); 3 | 4 | const init = async (app) => { 5 | app.use("/api/customers", authenticateRequest, routes); 6 | return app; 7 | }; 8 | 9 | module.exports = { init }; 10 | -------------------------------------------------------------------------------- /client/src/components/mega-menu/index.js: -------------------------------------------------------------------------------- 1 | export { default as MegaMenuDesktopVertical } from './MegaMenuDesktopVertical'; 2 | export { default as MegaMenuDesktopHorizon } from './MegaMenuDesktopHorizon'; 3 | export { default as MegaMenuMobile } from './MegaMenuMobile'; 4 | export { default as MenuConfig } from './MenuConfig'; 5 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/dto/updateLocationRelationship.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateLocationRelationshipDto } from './createLocationRelationship.dto'; 3 | 4 | export class UpdateLocationRelationshipDto extends PartialType( 5 | CreateLocationRelationshipDto, 6 | ) {} 7 | -------------------------------------------------------------------------------- /client/src/sections/about/index.js: -------------------------------------------------------------------------------- 1 | export { default as AboutHero } from './AboutHero'; 2 | export { default as AboutWhat } from './AboutWhat'; 3 | export { default as AboutTeam } from './AboutTeam'; 4 | export { default as AboutVision } from './AboutVision'; 5 | export { default as AboutTestimonials } from './AboutTestimonials'; 6 | -------------------------------------------------------------------------------- /server/db.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | mongodb: 4 | image: mongo 5 | container_name: mongodb 6 | ports: 7 | - 27000:27017 8 | networks: 9 | - mydockernet 10 | volumes: 11 | - app_mongo:/data/db 12 | networks: 13 | mydockernet: 14 | driver: bridge 15 | volumes: 16 | app_mongo: 17 | -------------------------------------------------------------------------------- /client/src/hooks/useCollapseDrawer.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { CollapseDrawerContext } from '../contexts/CollapseDrawerContext'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | const useCollapseDrawer = () => useContext(CollapseDrawerContext); 7 | 8 | export default useCollapseDrawer; 9 | -------------------------------------------------------------------------------- /server-nest/src/dto/getQueryDto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | 4 | export class GetQueryDto { 5 | @IsOptional() 6 | id: MongooseSchema.Types.ObjectId; 7 | 8 | @IsOptional() 9 | current?: number; 10 | 11 | @IsOptional() 12 | pageSize?: number; 13 | } 14 | -------------------------------------------------------------------------------- /server-nest/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Stepper.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Stepper(theme) { 4 | return { 5 | MuiStepConnector: { 6 | styleOverrides: { 7 | line: { 8 | borderColor: theme.palette.divider, 9 | }, 10 | }, 11 | }, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Select.js: -------------------------------------------------------------------------------- 1 | // 2 | import { InputSelectIcon } from './CustomIcons'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function Select() { 7 | return { 8 | MuiSelect: { 9 | defaultProps: { 10 | IconComponent: InputSelectIcon, 11 | }, 12 | }, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /server/src/core/event-manager.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require("events"); 2 | 3 | class EventManager { 4 | constructor() { 5 | if (!EventManager.instance) { 6 | EventManager.instance = new EventEmitter(); 7 | } 8 | } 9 | 10 | getInstance() { 11 | return EventManager.instance; 12 | } 13 | } 14 | 15 | module.exports = new EventManager(); 16 | -------------------------------------------------------------------------------- /client/public/icons/ic_user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Badge.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Badge() { 4 | return { 5 | MuiBadge: { 6 | styleOverrides: { 7 | dot: { 8 | width: 10, 9 | height: 10, 10 | borderRadius: '50%', 11 | }, 12 | }, 13 | }, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /server-nest/src/config/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Global, Module } from '@nestjs/common'; 2 | 3 | import { ConfigService } from './config.service'; 4 | 5 | @Global() 6 | @Module({ 7 | providers: [ 8 | { 9 | provide: ConfigService, 10 | useValue: new ConfigService(), 11 | }, 12 | ], 13 | exports: [ConfigService], 14 | }) 15 | export class ConfigModule {} 16 | -------------------------------------------------------------------------------- /client/src/components/animate/variants/path.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const TRANSITION = { 4 | duration: 2, 5 | ease: [0.43, 0.13, 0.23, 0.96] 6 | }; 7 | 8 | export const varPath = { 9 | animate: { 10 | fillOpacity: [0, 0, 1], 11 | pathLength: [1, 0.4, 0], 12 | transition: TRANSITION 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /client/src/utils/uuidv4.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // ---------------------------------------------------------------------- 3 | 4 | export default function uuidv4() { 5 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 6 | const r = (Math.random() * 16) | 0, 7 | v = c === 'x' ? r : (r & 0x3) | 0x8; 8 | return v.toString(16); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /server/src/core/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | const setup = async () => { 3 | const logger = require("./logger"); 4 | const eventEmitter = require("./event-manager").getInstance(); 5 | const app = require("./app"); 6 | const connectWithDb = require("./mongo"); 7 | return { app, eventEmitter, connectWithDb, logger }; 8 | }; 9 | 10 | module.exports = { setup }; 11 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/dto/createLocationRelationship.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNumber, IsNotEmpty } from 'class-validator'; 2 | 3 | export class CreateLocationRelationshipDto { 4 | @IsNumber() 5 | @IsNotEmpty() 6 | ancestor_id: number; 7 | 8 | @IsNumber() 9 | @IsNotEmpty() 10 | descendant_id: number; 11 | 12 | @IsNumber() 13 | @IsNotEmpty() 14 | distance: number; 15 | } 16 | -------------------------------------------------------------------------------- /server-nest/src/modules/user/dto/getUsers.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmpty, IsOptional, IsPositive } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | 4 | export class GetUsersDto { 5 | @IsOptional() 6 | id: MongooseSchema.Types.ObjectId; 7 | 8 | @IsOptional() 9 | current?: number; 10 | 11 | @IsOptional() 12 | @IsPositive() 13 | pageSize?: number; 14 | } 15 | -------------------------------------------------------------------------------- /server/.env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_PATH=server 2 | PORT=8080 3 | DB_HOST=localhost 4 | DB_PORT=27017 5 | DB_NAME=sabil 6 | IS_MONGODB_CLOUD_URL=false 7 | MONGODB_CLOUD_URL=mongodb+srv://:@cluster0.abcd.mongodb.net/myFirstDatabase?retryWrites=true 8 | SENDGRID_API_KEY=123 9 | DEFAULT_PAGE_SIZE=20 10 | 11 | JWT_SECRET=JWT_SECRETfsdfsdfsdsd3435353 12 | JWT_EXPIRES_IN=10000 13 | APP_NAME=Sabil 14 | -------------------------------------------------------------------------------- /client/src/components/animate/variants/index.js: -------------------------------------------------------------------------------- 1 | export * from './path'; 2 | export * from './fade'; 3 | export * from './zoom'; 4 | export * from './flip'; 5 | export * from './slide'; 6 | export * from './scale'; 7 | export * from './bounce'; 8 | export * from './rotate'; 9 | export * from './actions'; 10 | export * from './container'; 11 | export * from './transition'; 12 | export * from './background'; 13 | -------------------------------------------------------------------------------- /client/src/hooks/useIsMountedRef.js: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from 'react'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function useIsMountedRef() { 6 | const isMounted = useRef(true); 7 | 8 | useEffect( 9 | () => () => { 10 | isMounted.current = false; 11 | }, 12 | [] 13 | ); 14 | 15 | return isMounted; 16 | } 17 | -------------------------------------------------------------------------------- /client/src/utils/highlight.js: -------------------------------------------------------------------------------- 1 | import hljs from 'highlight.js'; 2 | import 'highlight.js/styles/atom-one-dark-reasonable.css'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | hljs.configure({ 7 | languages: ['javascript', 'jsx', 'sh', 'bash', 'html', 'scss', 'css', 'json'], 8 | }); 9 | 10 | if (typeof window !== 'undefined') { 11 | window.hljs = hljs; 12 | } 13 | -------------------------------------------------------------------------------- /client/src/components/ScrollToTop.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { useLocation } from 'react-router-dom'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function ScrollToTop() { 7 | const { pathname } = useLocation(); 8 | 9 | useEffect(() => { 10 | window.scrollTo(0, 0); 11 | }, [pathname]); 12 | 13 | return null; 14 | } 15 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Breadcrumbs.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Breadcrumbs(theme) { 4 | return { 5 | MuiBreadcrumbs: { 6 | styleOverrides: { 7 | separator: { 8 | marginLeft: theme.spacing(2), 9 | marginRight: theme.spacing(2), 10 | }, 11 | }, 12 | }, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /server-nest/src/modules/customer/dto/updateCustomer.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateCustomerDto } from './createCustomer.dto'; 3 | import { IsOptional } from 'class-validator'; 4 | import { Schema as MongooseSchema } from 'mongoose'; 5 | 6 | export class UpdateCustomerDto extends PartialType(CreateCustomerDto) { 7 | @IsOptional() id: MongooseSchema.Types.ObjectId; 8 | } 9 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Popover.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Popover(theme) { 4 | return { 5 | MuiPopover: { 6 | styleOverrides: { 7 | paper: { 8 | boxShadow: theme.customShadows.dropdown, 9 | borderRadius: Number(theme.shape.borderRadius) * 1.5, 10 | }, 11 | }, 12 | }, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /server-nest/src/modules/customer/dto/createCustomer.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | 3 | export class CreateCustomerDto { 4 | @IsOptional() firstName: string; 5 | @IsOptional() lastName: string; 6 | @IsOptional() city: string; 7 | @IsOptional() state: string; 8 | @IsOptional() zip: string; 9 | @IsOptional() phone: string; 10 | @IsOptional() email: string; 11 | @IsOptional() ip: string; 12 | } 13 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/dto/createLocation.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsNotEmpty } from 'class-validator'; 2 | 3 | export class CreateLocationDto { 4 | @IsString() 5 | @IsNotEmpty() 6 | building: string; 7 | 8 | @IsString() 9 | @IsNotEmpty() 10 | location_name: string; 11 | 12 | @IsString() 13 | @IsNotEmpty() 14 | location_number: string; 15 | 16 | @IsString() 17 | @IsNotEmpty() 18 | area: string; 19 | } 20 | -------------------------------------------------------------------------------- /server/test/app/controller/routes.test.js: -------------------------------------------------------------------------------- 1 | const contactRouter = require('../../../src/routes/contact-route'); 2 | 3 | describe('Routes', () => { 4 | 5 | // contact routes setup ok 6 | test('contact routes setup ok', () => { 7 | const routes = contactRouter.stack 8 | .filter(layer => layer.route) 9 | .map(layer => layer.route.path); 10 | expect(routes.includes('/search')).toBe(true) 11 | }) 12 | 13 | }) 14 | 15 | -------------------------------------------------------------------------------- /client/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts as build 2 | WORKDIR /usr/src/app 3 | ARG REACT_APP_API_URL 4 | # ENV PATH /usr/src/app/node_modules/.bin:$PATH 5 | COPY package*.json ./ 6 | RUN npm install 7 | COPY . . 8 | 9 | EXPOSE 8001 10 | CMD [ "npm", "run", "start" ] 11 | 12 | # production environment 13 | # FROM nginx:stable-alpine 14 | # COPY --from=build /usr/src/app/build /usr/share/nginx/html 15 | # EXPOSE 80 16 | # CMD ["nginx", "-g", "daemon off;"] 17 | -------------------------------------------------------------------------------- /client/src/_mock/funcs.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export function randomNumber(number) { 4 | return Math.floor(Math.random() * number) + 1; 5 | } 6 | 7 | export function randomNumberRange(min, max) { 8 | return Math.floor(Math.random() * (max - min + 1)) + min; 9 | } 10 | 11 | export function randomInArray(array) { 12 | return array[Math.floor(Math.random() * array.length)]; 13 | } 14 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Skeleton.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Skeleton(theme) { 4 | return { 5 | MuiSkeleton: { 6 | defaultProps: { 7 | animation: 'wave', 8 | }, 9 | 10 | styleOverrides: { 11 | root: { 12 | backgroundColor: theme.palette.background.neutral, 13 | }, 14 | }, 15 | }, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /client/src/components/map/index.js: -------------------------------------------------------------------------------- 1 | export { default as MapControlPopup } from './MapControlPopup'; 2 | export { default as MapControlScale } from './MapControlScale'; 3 | export { default as MapControlMarker } from './MapControlMarker'; 4 | export { default as MapControlGeolocate } from './MapControlGeolocate'; 5 | export { default as MapControlFullscreen } from './MapControlFullscreen'; 6 | export { default as MapControlNavigation } from './MapControlNavigation'; 7 | -------------------------------------------------------------------------------- /client/src/helpers/checkPermission.js: -------------------------------------------------------------------------------- 1 | export function checkPermissionAccess(path){ 2 | const permissions = JSON.parse(localStorage.getItem("permissions")) 3 | console.log('checkPermissionAccess---', permissions); 4 | return true; // todo - remove when role ready 5 | // eslint-disable-next-line no-unreachable 6 | return permissions && Array.isArray(permissions) 7 | && permissions.some((permission) => permission.resourceName === path); 8 | } -------------------------------------------------------------------------------- /client/src/sections/@dashboard/e-commerce/shop/index.js: -------------------------------------------------------------------------------- 1 | export { default as ShopTagFiltered } from './ShopTagFiltered'; 2 | export { default as ShopProductCard } from './ShopProductCard'; 3 | export { default as ShopProductList } from './ShopProductList'; 4 | export { default as ShopProductSort } from './ShopProductSort'; 5 | export { default as ShopFilterSidebar } from './ShopFilterSidebar'; 6 | export { default as ShopProductSearch } from './ShopProductSearch'; 7 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Typography.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Typography(theme) { 4 | return { 5 | MuiTypography: { 6 | styleOverrides: { 7 | paragraph: { 8 | marginBottom: theme.spacing(2), 9 | }, 10 | gutterBottom: { 11 | marginBottom: theme.spacing(1), 12 | }, 13 | }, 14 | }, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /server/src/modules/resource/request.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const schema = Joi.object().keys({ 4 | _id: Joi.string().optional(), 5 | name: Joi.string().min(2).max(30).required(), 6 | alias: Joi.string().required(), 7 | type: Joi.string().required(), 8 | }); 9 | 10 | const validate = (data) => { 11 | const result = schema.validate(data); 12 | result.value = data; 13 | return result; 14 | }; 15 | 16 | module.exports = { validate }; 17 | -------------------------------------------------------------------------------- /server/src/modules/resource/service.js: -------------------------------------------------------------------------------- 1 | const { name } = require("./model"); 2 | 3 | const getQuery = (payload) => { 4 | let query = {}; 5 | if (payload.name) { 6 | query = { 7 | $or: [ 8 | { name: { $regex: payload.name, $options: "i" } }, 9 | { alias: { $regex: payload.name, $options: "i" } }, 10 | ], 11 | }; 12 | } 13 | return query; 14 | }; 15 | 16 | module.exports = { 17 | getQuery, 18 | modelName: name, 19 | }; 20 | -------------------------------------------------------------------------------- /client/src/components/hook-form/index.js: -------------------------------------------------------------------------------- 1 | export * from './RHFCheckbox'; 2 | export * from './RHFUpload'; 3 | 4 | export { default as FormProvider } from './FormProvider'; 5 | 6 | export { default as RHFSwitch } from './RHFSwitch'; 7 | export { default as RHFSelect } from './RHFSelect'; 8 | export { default as RHFEditor } from './RHFEditor'; 9 | export { default as RHFTextField } from './RHFTextField'; 10 | export { default as RHFRadioGroup } from './RHFRadioGroup'; 11 | -------------------------------------------------------------------------------- /server-nest/src/modules/resource/dto/createResource.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | 4 | export class CreateResourceDto { 5 | @IsOptional() id: MongooseSchema.Types.ObjectId; 6 | @IsOptional() name: string; 7 | @IsOptional() alias: string; 8 | @IsOptional() type: string; 9 | @IsOptional() createdBy: MongooseSchema.Types.ObjectId; 10 | @IsOptional() updatedBy: MongooseSchema.Types.ObjectId; 11 | } 12 | -------------------------------------------------------------------------------- /client/src/_mock/index.js: -------------------------------------------------------------------------------- 1 | import _mock from './_mock'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export * from './_app'; 6 | export * from './_user'; 7 | export * from './_plans'; 8 | export * from './_others'; 9 | export * from './_booking'; 10 | export * from './_banking'; 11 | export * from './_ecommerce'; 12 | export * from './_analytics'; 13 | export * from './_countries'; 14 | export * from './_top100Films'; 15 | 16 | export default _mock; 17 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Radio.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Radio(theme) { 4 | return { 5 | MuiRadio: { 6 | styleOverrides: { 7 | root: { 8 | padding: theme.spacing(1), 9 | svg: { 10 | fontSize: 24, 11 | '&[font-size=small]': { 12 | fontSize: 20, 13 | }, 14 | }, 15 | }, 16 | }, 17 | }, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /client/src/utils/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | // config 3 | import { HOST_API } from '../config'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | const axiosInstance = axios.create({ 8 | baseURL: HOST_API, 9 | }); 10 | 11 | axiosInstance.interceptors.response.use( 12 | (response) => response, 13 | (error) => Promise.reject((error.response && error.response.data) || 'Something went wrong') 14 | ); 15 | 16 | export default axiosInstance; 17 | -------------------------------------------------------------------------------- /server/test/mock-routes/routes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const router = express.Router(); 4 | const { router: userMockRoutes } = require("./user-controller-mock"); 5 | const { router: productMockRoutes } = require("./product-controller-mock"); 6 | const { router: blogMockRoutes } = require("./blog-controller-mock"); 7 | 8 | router.use("/users", userMockRoutes); 9 | router.use("/products", productMockRoutes); 10 | router.use("/blogs", blogMockRoutes); 11 | 12 | module.exports = router; 13 | -------------------------------------------------------------------------------- /server-nest/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | 3 | import { AppModule } from './app.module'; 4 | import { ConfigService } from './config/config.service'; 5 | 6 | async function bootstrap() { 7 | const app = await NestFactory.create(AppModule, { 8 | cors: true, 9 | // logger: ['log', 'error', 'warn', 'debug', 'verbose'], 10 | logger: console, 11 | }); 12 | const config = new ConfigService(); 13 | await app.listen(await config.getPortConfig()); 14 | } 15 | bootstrap(); 16 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Timeline.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Timeline(theme) { 4 | return { 5 | MuiTimelineDot: { 6 | styleOverrides: { 7 | root: { 8 | boxShadow: 'none', 9 | }, 10 | }, 11 | }, 12 | 13 | MuiTimelineConnector: { 14 | styleOverrides: { 15 | root: { 16 | backgroundColor: theme.palette.divider, 17 | }, 18 | }, 19 | }, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Menu.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Menu(theme) { 4 | return { 5 | MuiMenuItem: { 6 | styleOverrides: { 7 | root: { 8 | '&.Mui-selected': { 9 | backgroundColor: theme.palette.action.selected, 10 | '&:hover': { 11 | backgroundColor: theme.palette.action.hover, 12 | }, 13 | }, 14 | }, 15 | }, 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/theme/overrides/SvgIcon.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function SvgIcon() { 4 | return { 5 | MuiSvgIcon: { 6 | styleOverrides: { 7 | fontSizeSmall: { 8 | width: 20, 9 | height: 20, 10 | fontSize: 'inherit', 11 | }, 12 | fontSizeLarge: { 13 | width: 32, 14 | height: 32, 15 | fontSize: 'inherit', 16 | }, 17 | }, 18 | }, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/components/nav-section/index.js: -------------------------------------------------------------------------------- 1 | import { matchPath } from 'react-router-dom'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export { default as NavSectionVertical } from './vertical'; 6 | export { default as NavSectionHorizontal } from './horizontal'; 7 | 8 | export function isExternalLink(path) { 9 | return path.includes('http'); 10 | } 11 | 12 | export function getActive(path, pathname) { 13 | return path ? !!matchPath({ path, end: false }, pathname) : false; 14 | } 15 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonMailSidebarItem.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Stack, Skeleton } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonMailSidebarItem() { 7 | return ( 8 | 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "React Material Minimal UI", 3 | "short_name": "Minimal-UI", 4 | "display": "standalone", 5 | "start_url": "/", 6 | "theme_color": "#000000", 7 | "background_color": "#ffffff", 8 | "icons": [ 9 | { 10 | "src": "favicon/android-chrome-192x192.png", 11 | "sizes": "192x192", 12 | "type": "image/png" 13 | }, 14 | { 15 | "src": "favicon/android-chrome-512x512.png", 16 | "sizes": "512x512", 17 | "type": "image/png" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonMap.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Stack, Skeleton } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonMap() { 7 | return ( 8 | 9 | {[...Array(5)].map((_, index) => ( 10 | 15 | ))} 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Tooltip.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Tooltip(theme) { 4 | const isLight = theme.palette.mode === 'light'; 5 | 6 | return { 7 | MuiTooltip: { 8 | styleOverrides: { 9 | tooltip: { 10 | backgroundColor: theme.palette.grey[isLight ? 800 : 700], 11 | }, 12 | arrow: { 13 | color: theme.palette.grey[isLight ? 800 : 700], 14 | }, 15 | }, 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/e-commerce/product-details/index.js: -------------------------------------------------------------------------------- 1 | export { default as ProductDetailsReview } from './ProductDetailsReview'; 2 | export { default as ProductDetailsSummary } from './ProductDetailsSummary'; 3 | export { default as ProductDetailsCarousel } from './ProductDetailsCarousel'; 4 | export { default as ProductDetailsReviewForm } from './ProductDetailsReview'; 5 | export { default as ProductDetailsReviewList } from './ProductDetailsReviewList'; 6 | export { default as ProductDetailsReviewOverview } from './ProductDetailsReviewOverview'; 7 | -------------------------------------------------------------------------------- /client/src/components/Iconify.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // icons 3 | import { Icon } from '@iconify/react'; 4 | // @mui 5 | import { Box } from '@mui/material'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | Iconify.propTypes = { 10 | icon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]), 11 | sx: PropTypes.object, 12 | }; 13 | 14 | export default function Iconify({ icon, sx, ...other }) { 15 | return ; 16 | } 17 | -------------------------------------------------------------------------------- /server/src/modules/role/request.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const schema = Joi.object().keys({ 4 | _id: Joi.string().optional(), 5 | name: Joi.string().min(2).max(30).required(), 6 | alias: Joi.string().required(), 7 | }); 8 | 9 | const validate = (data, user) => { 10 | const result = schema.validate(data); 11 | result.value = { 12 | ...data, 13 | isSuperAdmin: false, 14 | isAdmin: false, 15 | createdBy: user.id, 16 | updatedBy: user.id, 17 | }; 18 | return result; 19 | }; 20 | 21 | module.exports = { validate }; 22 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Paper.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Paper(theme) { 4 | return { 5 | MuiPaper: { 6 | defaultProps: { 7 | elevation: 0, 8 | }, 9 | 10 | variants: [ 11 | { 12 | props: { variant: 'outlined' }, 13 | style: { borderColor: theme.palette.grey[500_12] }, 14 | }, 15 | ], 16 | 17 | styleOverrides: { 18 | root: { 19 | backgroundImage: 'none', 20 | }, 21 | }, 22 | }, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /client/public/fonts/index.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'CircularStd'; 3 | font-weight: 400; 4 | font-style: normal; 5 | src: local('CircularStd'), url('CircularStd-Book.otf') format('opentype'); 6 | } 7 | @font-face { 8 | font-family: 'CircularStd'; 9 | font-weight: 500; 10 | font-style: normal; 11 | src: local('CircularStd'), url('CircularStd-Medium.otf') format('opentype'); 12 | } 13 | @font-face { 14 | font-family: 'CircularStd'; 15 | font-weight: 700; 16 | font-style: normal; 17 | src: local('CircularStd'), url('CircularStd-Bold.otf') format('opentype'); 18 | } 19 | -------------------------------------------------------------------------------- /client/src/theme/overrides/LoadingButton.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function LoadingButton() { 4 | return { 5 | MuiLoadingButton: { 6 | styleOverrides: { 7 | root: { 8 | '&.MuiButton-text': { 9 | '& .MuiLoadingButton-startIconPendingStart': { 10 | marginLeft: 0, 11 | }, 12 | '& .MuiLoadingButton-endIconPendingEnd': { 13 | marginRight: 0, 14 | }, 15 | }, 16 | }, 17 | }, 18 | }, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/components/skeleton/index.js: -------------------------------------------------------------------------------- 1 | export { default as SkeletonMap } from './SkeletonMap'; 2 | export { default as SkeletonPost } from './SkeletonPost'; 3 | export { default as SkeletonProduct } from './SkeletonProduct'; 4 | export { default as SkeletonPostItem } from './SkeletonPostItem'; 5 | export { default as SkeletonProductItem } from './SkeletonProductItem'; 6 | export { default as SkeletonKanbanColumn } from './SkeletonKanbanColumn'; 7 | export { default as SkeletonMailSidebarItem } from './SkeletonMailSidebarItem'; 8 | export { default as SkeletonConversationItem } from './SkeletonConversationItem'; 9 | -------------------------------------------------------------------------------- /server/src/modules/blog/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | const { name: ModelName } = require("./model"); 7 | 8 | const processRequest = async (req, res, next) => { 9 | req.modelName = ModelName; 10 | return next(); 11 | }; 12 | 13 | const init = async (app) => { 14 | app.use( 15 | "/api/blogs", 16 | authenticateRequest, 17 | // authorizeRequest, 18 | processRequest, 19 | routes 20 | ); 21 | return app; 22 | }; 23 | 24 | module.exports = { init }; 25 | -------------------------------------------------------------------------------- /server/src/modules/product/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | const { name: ModelName } = require("./model"); 7 | 8 | const processRequest = async (req, res, next) => { 9 | req.modelName = ModelName; 10 | return next(); 11 | }; 12 | 13 | const init = async (app) => { 14 | app.use( 15 | "/api/products", 16 | authenticateRequest, 17 | authorizeRequest, 18 | processRequest, 19 | routes 20 | ); 21 | return app; 22 | }; 23 | 24 | module.exports = { init }; 25 | -------------------------------------------------------------------------------- /client/src/components/hook-form/FormProvider.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // form 3 | import { FormProvider as Form } from 'react-hook-form'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | FormProvider.propTypes = { 8 | children: PropTypes.node.isRequired, 9 | methods: PropTypes.object.isRequired, 10 | onSubmit: PropTypes.func, 11 | }; 12 | 13 | export default function FormProvider({ children, onSubmit, methods }) { 14 | return ( 15 |
16 | {children}
17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /server/src/modules/payment/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | const { name: ModelName } = require("./model"); 7 | 8 | const processRequest = async (req, res, next) => { 9 | req.modelName = ModelName; 10 | return next(); 11 | }; 12 | 13 | const init = async (app) => { 14 | app.use( 15 | "/api/payments", 16 | authenticateRequest, 17 | // authorizeRequest, 18 | processRequest, 19 | routes 20 | ); 21 | return app; 22 | }; 23 | 24 | module.exports = { init }; 25 | -------------------------------------------------------------------------------- /server/src/modules/role/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | 7 | const { name: ModelName } = require("./model"); 8 | 9 | const processRequest = async (req, res, next) => { 10 | req.modelName = ModelName; 11 | return next(); 12 | }; 13 | 14 | const init = async (app) => { 15 | app.use( 16 | "/api/roles", 17 | authenticateRequest, 18 | // authorizeRequest, 19 | processRequest, 20 | routes 21 | ); 22 | return app; 23 | }; 24 | 25 | module.exports = { init }; 26 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/location.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | import { Location } from './entity/location.entity'; 4 | import { LocationRelationship } from './entity/locationRelationship.entity'; 5 | import { LocationController } from './location.controller'; 6 | import { LocationService } from './location.service'; 7 | 8 | @Module({ 9 | imports: [TypeOrmModule.forFeature([Location, LocationRelationship])], 10 | controllers: [LocationController], 11 | providers: [LocationService], 12 | }) 13 | export class LocationModule {} 14 | -------------------------------------------------------------------------------- /server/src/modules/permission/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | const { name: ModelName } = require("./model"); 7 | 8 | const processRequest = async (req, res, next) => { 9 | req.modelName = ModelName; 10 | return next(); 11 | }; 12 | 13 | const init = async (app) => { 14 | app.use( 15 | "/api/permissions", 16 | authenticateRequest, 17 | authorizeRequest, 18 | processRequest, 19 | routes 20 | ); 21 | return app; 22 | }; 23 | 24 | module.exports = { init }; 25 | -------------------------------------------------------------------------------- /server/src/modules/salesOrder/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | const { name: ModelName } = require("./model"); 7 | 8 | const processRequest = async (req, res, next) => { 9 | req.modelName = ModelName; 10 | return next(); 11 | }; 12 | 13 | const init = async (app) => { 14 | app.use( 15 | "/api/sales-orders", 16 | authenticateRequest, 17 | // authorizeRequest, 18 | processRequest, 19 | routes 20 | ); 21 | return app; 22 | }; 23 | 24 | module.exports = { init }; 25 | -------------------------------------------------------------------------------- /server/src/modules/resource/index.js: -------------------------------------------------------------------------------- 1 | const routes = require("./controller"); 2 | const { 3 | authenticateRequest, 4 | authorizeRequest, 5 | } = require("../../common/middlewares"); 6 | 7 | const { name: ModelName } = require("./model"); 8 | 9 | const processRequest = async (req, res, next) => { 10 | req.modelName = ModelName; 11 | return next(); 12 | }; 13 | 14 | const init = async (app) => { 15 | app.use( 16 | "/api/resources", 17 | authenticateRequest, 18 | // authorizeRequest, 19 | processRequest, 20 | routes 21 | ); 22 | return app; 23 | }; 24 | 25 | module.exports = { init }; 26 | -------------------------------------------------------------------------------- /server-nest/src/modules/role/dto/createRole.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | 4 | export class CreateRoleDto { 5 | @IsOptional() id: MongooseSchema.Types.ObjectId; 6 | @IsOptional() name: string; 7 | @IsOptional() title: string; 8 | @IsOptional() isSuperAdmin: boolean; 9 | @IsOptional() isAdmin: boolean; 10 | @IsOptional() alias: string; 11 | @IsOptional() permissions: MongooseSchema.Types.ObjectId[]; 12 | @IsOptional() createdBy: MongooseSchema.Types.ObjectId; 13 | @IsOptional() updatedBy: MongooseSchema.Types.ObjectId; 14 | } 15 | -------------------------------------------------------------------------------- /server/src/email/sendgrid.js: -------------------------------------------------------------------------------- 1 | const sgMail = require("@sendgrid/mail"); 2 | 3 | sgMail.setApiKey(process.env.SENDGRID_API_KEY); 4 | const msg = { 5 | to: "foyzulkarim@gmail.com", // Change to your recipient 6 | from: "info@bizbook365.com", // Change to your verified sender 7 | subject: "Sending with SendGrid is Fun", 8 | text: "and easy to do anywhere, even with Node.js", 9 | html: "and easy to do anywhere, even with Node.js", 10 | }; 11 | sgMail 12 | .send(msg) 13 | .then(() => { 14 | console.log("Email sent"); 15 | }) 16 | .catch((error) => { 17 | console.error(error); 18 | }); 19 | -------------------------------------------------------------------------------- /client/src/sections/home/index.js: -------------------------------------------------------------------------------- 1 | export { default as HomeHero } from './HomeHero'; 2 | export { default as HomeMinimal } from './HomeMinimal'; 3 | export { default as HomeDarkMode } from './HomeDarkMode'; 4 | export { default as HomeLookingFor } from './HomeLookingFor'; 5 | export { default as HomeColorPresets } from './HomeColorPresets'; 6 | export { default as HomePricingPlans } from './HomePricingPlans'; 7 | export { default as HomeAdvertisement } from './HomeAdvertisement'; 8 | export { default as HomeCleanInterfaces } from './HomeCleanInterfaces'; 9 | export { default as HomeHugePackElements } from './HomeHugePackElements'; 10 | -------------------------------------------------------------------------------- /client/src/components/animate/MotionLazyContainer.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { LazyMotion } from 'framer-motion'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | // eslint-disable-next-line import/extensions 7 | const loadFeatures = () => import('./features.js').then((res) => res.default); 8 | 9 | MotionLazyContainer.propTypes = { 10 | children: PropTypes.node 11 | }; 12 | 13 | export default function MotionLazyContainer({ children }) { 14 | return ( 15 | 16 | {children} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /client/src/components/animate/index.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export * from './variants'; 4 | 5 | export { default as DialogAnimate } from './DialogAnimate'; 6 | export { default as TextAnimate } from './TextAnimate'; 7 | 8 | export { default as FabButtonAnimate } from './FabButtonAnimate'; 9 | export { default as IconButtonAnimate } from './IconButtonAnimate'; 10 | 11 | export { default as MotionInView } from './MotionInView'; 12 | export { default as MotionContainer } from './MotionContainer'; 13 | export { default as MotionLazyContainer } from './MotionLazyContainer'; 14 | -------------------------------------------------------------------------------- /server-nest/.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=server-nest 2 | PROJECT_PATH=server 3 | PORT=8080 4 | DEFAULT_PAGE_SIZE=20 5 | 6 | MONGODB_HOST=localhost 7 | MONGODB_PORT=27017 8 | MONGODB_PASSWORD=strongpassword 9 | MONGODB_USER=admin 10 | MONGODB_NAME=test 11 | IS_MONGODB_CLOUD_URL=true 12 | MONGODB_CLOUD_URL=mongodb+srv://:@cluster0.abcd.mongodb.net/myFirstDatabase?retryWrites=true 13 | 14 | POSTGRES_HOST=localhost 15 | POSTGRES_PORT=5432 16 | POSTGRES_USERNAME=postgres 17 | POSTGRES_PASSWORD= 18 | POSTGRES_DATABASE=sabil 19 | 20 | SENDGRID_API_KEY=123 21 | 22 | JWT_SECRET=JWT_SECRETfsdfsdfsdsd3435353 23 | JWT_EXPIRES_IN=10000 24 | -------------------------------------------------------------------------------- /client/src/components/animate/variants/container.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const varContainer = (props) => { 4 | const staggerIn = props?.staggerIn || 0.05; 5 | const delayIn = props?.staggerIn || 0.05; 6 | const staggerOut = props?.staggerIn || 0.05; 7 | 8 | return { 9 | animate: { 10 | transition: { 11 | staggerChildren: staggerIn, 12 | delayChildren: delayIn 13 | } 14 | }, 15 | exit: { 16 | transition: { 17 | staggerChildren: staggerOut, 18 | staggerDirection: -1 19 | } 20 | } 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonPostItem.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Box, Skeleton, Grid } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonPostItem() { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /client/src/guards/GuestGuard.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Navigate } from 'react-router-dom'; 3 | // hooks 4 | import useAuth from '../hooks/useAuth'; 5 | // routes 6 | import { PATH_DASHBOARD } from '../routes/paths'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | GuestGuard.propTypes = { 11 | children: PropTypes.node 12 | }; 13 | 14 | export default function GuestGuard({ children }) { 15 | const { isAuthenticated } = useAuth(); 16 | 17 | if (isAuthenticated) { 18 | return ; 19 | } 20 | 21 | return <>{children}; 22 | } 23 | -------------------------------------------------------------------------------- /client/src/hooks/useAuth.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | // 3 | import { AuthContext } from '../contexts/JWTContext'; 4 | // import { AuthContext } from '../contexts/FirebaseContext'; 5 | // import { AuthContext } from '../contexts/Auth0Context'; 6 | // import { AuthContext } from '../contexts/AwsCognitoContext'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | const useAuth = () => { 11 | const context = useContext(AuthContext); 12 | 13 | if (!context) throw new Error('Auth context must be use inside AuthProvider'); 14 | 15 | return context; 16 | }; 17 | 18 | export default useAuth; 19 | -------------------------------------------------------------------------------- /client/public/icons/ic_mail.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-nest/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/src/modules/customer/request.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const schema = Joi.object().keys({ 4 | name: Joi.string().required(), 5 | phone: Joi.string().required(), 6 | email: Joi.string().required(), 7 | address: Joi.string().required(), 8 | area: Joi.string().required(), 9 | city: Joi.string().required(), 10 | state: Joi.string().required(), 11 | postcode: Joi.string().alphanum().required(), 12 | country: Joi.string().required(), 13 | }); 14 | 15 | const validate = (data) => { 16 | const result = schema.validate(data); 17 | result.value = data; 18 | return result; 19 | }; 20 | 21 | module.exports = { validate }; 22 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Autocomplete.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Autocomplete(theme) { 4 | return { 5 | MuiAutocomplete: { 6 | styleOverrides: { 7 | paper: { 8 | boxShadow: theme.customShadows.dropdown, 9 | }, 10 | listbox: { 11 | padding: theme.spacing(0, 1), 12 | '& .MuiAutocomplete-option': { 13 | padding: theme.spacing(1), 14 | margin: theme.spacing(1, 0), 15 | borderRadius: theme.shape.borderRadius, 16 | }, 17 | }, 18 | }, 19 | }, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /client/src/_mock/boolean.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const boolean = [ 4 | true, 5 | true, 6 | true, 7 | false, 8 | false, 9 | true, 10 | false, 11 | false, 12 | false, 13 | false, 14 | true, 15 | true, 16 | true, 17 | false, 18 | false, 19 | false, 20 | true, 21 | false, 22 | false, 23 | false, 24 | true, 25 | false, 26 | false, 27 | true, 28 | true, 29 | true, 30 | false, 31 | false, 32 | true, 33 | true, 34 | false, 35 | true, 36 | false, 37 | true, 38 | true, 39 | true, 40 | false, 41 | true, 42 | false, 43 | false 44 | ]; 45 | -------------------------------------------------------------------------------- /client/src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "demo": { 3 | "title": "English", 4 | "introduction": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/user/account/index.js: -------------------------------------------------------------------------------- 1 | export { default as AccountBilling } from './AccountBilling'; 2 | export { default as AccountBillingAddressBook } from './AccountBillingAddressBook'; 3 | export { default as AccountBillingInvoiceHistory } from './AccountBillingInvoiceHistory'; 4 | export { default as AccountBillingPaymentMethod } from './AccountBillingPaymentMethod'; 5 | export { default as AccountChangePassword } from './AccountChangePassword'; 6 | export { default as AccountGeneral } from './AccountGeneral'; 7 | export { default as AccountNotifications } from './AccountNotifications'; 8 | export { default as AccountSocialLinks } from './AccountSocialLinks'; 9 | -------------------------------------------------------------------------------- /server-nest/src/modules/blog/blog.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { Blog, BlogSchema } from './entity/blog.entity'; 5 | import { BlogRepository } from './repository/blog.repository'; 6 | import { BlogController } from './blog.controller'; 7 | import { BlogService } from './blog.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]), 12 | ], 13 | controllers: [BlogController], 14 | providers: [BlogService, BlogRepository], 15 | exports: [BlogService, BlogRepository], 16 | }) 17 | export class BlogModule {} 18 | -------------------------------------------------------------------------------- /server-nest/src/modules/role/role.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { Role, RoleSchema } from './entity/role.entity'; 5 | import { RoleRepository } from './repository/role.repository'; 6 | import { RoleController } from './role.controller'; 7 | import { RoleService } from './role.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([{ name: Role.name, schema: RoleSchema }]), 12 | ], 13 | controllers: [RoleController], 14 | providers: [RoleService, RoleRepository], 15 | exports: [RoleService, RoleRepository], 16 | }) 17 | export class RoleModule {} 18 | -------------------------------------------------------------------------------- /server-nest/src/modules/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { User, UserSchema } from './entity/user.entity'; 5 | import { UserRepository } from './repository/user.repository'; 6 | import { UserController } from './user.controller'; 7 | import { UserService } from './user.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), 12 | ], 13 | controllers: [UserController], 14 | providers: [UserService, UserRepository], 15 | exports: [UserService, UserRepository], 16 | }) 17 | export class UserModule {} 18 | -------------------------------------------------------------------------------- /client/src/components/MyAvatar.js: -------------------------------------------------------------------------------- 1 | // hooks 2 | import useAuth from '../hooks/useAuth'; 3 | // utils 4 | import createAvatar from '../utils/createAvatar'; 5 | // 6 | import Avatar from './Avatar'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | export default function MyAvatar({ ...other }) { 11 | const { user } = useAuth(); 12 | 13 | return ( 14 | 20 | {createAvatar(user?.displayName).name} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/general/banking/index.js: -------------------------------------------------------------------------------- 1 | export { default as BankingContacts } from './BankingContacts'; 2 | export { default as BankingQuickTransfer } from './BankingQuickTransfer'; 3 | export { default as BankingInviteFriends } from './BankingInviteFriends'; 4 | export { default as BankingWidgetSummary } from './BankingWidgetSummary'; 5 | export { default as BankingCurrentBalance } from './BankingCurrentBalance'; 6 | export { default as BankingBalanceStatistics } from './BankingBalanceStatistics'; 7 | export { default as BankingRecentTransitions } from './BankingRecentTransitions'; 8 | export { default as BankingExpensesCategories } from './BankingExpensesCategories'; 9 | -------------------------------------------------------------------------------- /client/src/sections/payment/PaymentBillingAddress.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Typography, TextField, Stack } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function PaymentBillingAddress() { 7 | return ( 8 |
9 | Billing Address 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [shakilhasan] 4 | patreon: mdshakilhasan 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonConversationItem.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Stack, Skeleton } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonConversationItem() { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /client/src/theme/overrides/ControlLabel.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function ControlLabel(theme) { 4 | return { 5 | MuiFormControlLabel: { 6 | styleOverrides: { 7 | label: { 8 | ...theme.typography.body2, 9 | }, 10 | }, 11 | }, 12 | MuiFormHelperText: { 13 | styleOverrides: { 14 | root: { 15 | marginTop: theme.spacing(1), 16 | }, 17 | }, 18 | }, 19 | MuiFormLabel: { 20 | styleOverrides: { 21 | root: { 22 | color: theme.palette.text.disabled, 23 | }, 24 | }, 25 | }, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/utils/formatNumber.js: -------------------------------------------------------------------------------- 1 | import numeral from 'numeral'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export function fCurrency(number) { 6 | return numeral(number).format(Number.isInteger(number) ? '$0,0' : '$0,0.00'); 7 | } 8 | 9 | export function fPercent(number) { 10 | return numeral(number / 100).format('0.0%'); 11 | } 12 | 13 | export function fNumber(number) { 14 | return numeral(number).format(); 15 | } 16 | 17 | export function fShortenNumber(number) { 18 | return numeral(number).format('0.00a').replace('.00', ''); 19 | } 20 | 21 | export function fData(number) { 22 | return numeral(number).format('0.0 b'); 23 | } 24 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/guards/jwt-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExecutionContext, 3 | Injectable, 4 | UnauthorizedException, 5 | } from '@nestjs/common'; 6 | import { AuthGuard } from '@nestjs/passport'; 7 | 8 | @Injectable() 9 | export class JwtAuthGuard extends AuthGuard('jwt') { 10 | canActivate(context: ExecutionContext) { 11 | // Add your custom authentication logic here 12 | // for example, call super.logIn(request) to establish a session. 13 | return super.canActivate(context); 14 | } 15 | 16 | handleRequest(err, user, info) { 17 | if (err || !user) { 18 | throw err || new UnauthorizedException(); 19 | } 20 | return user; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | appserver: 4 | image: appserver:pi 5 | container_name: appserver 6 | build: 7 | context: . 8 | dockerfile: Dockerfile 9 | ports: 10 | - 8008:8008 11 | environment: 12 | - DEBUG=1 13 | - NODE_ENV=production 14 | - TEST=test123 15 | - DB_HOST=172.17.0.1 16 | - DB_PORT=27000 17 | - DB_NAME=sabil 18 | - JWT_SECRET=JWT_SECRETfsdfsdfsdsd3435353 19 | - JWT_EXPIRES_IN=3600 20 | - PORT=8008 21 | - IS_MONGODB_CLOUD_URL=false 22 | - MONGODB_CLOUD_URL=mongodb+srv://shakilhasan:sH1404087@cluster0.9r8bg.mongodb.net/sabil?retryWrites=true&w=majority 23 | -------------------------------------------------------------------------------- /server/src/modules/payment/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | // schema 4 | const schema = new mongoose.Schema( 5 | { 6 | title: { type: String, required: true }, 7 | description: { type: String, required: false }, // todo: required: true 8 | }, 9 | { timestamps: true } 10 | ); 11 | 12 | // indices 13 | // text index for name 14 | schema.index({ title: "text" }); 15 | 16 | // index for createdAt and updatedAt 17 | schema.index({ createdAt: 1 }); 18 | schema.index({ updatedAt: 1 }); 19 | 20 | // reference model 21 | const Payment = mongoose.model("Payment", schema); 22 | const ModelName = "Payment"; 23 | 24 | module.exports = { Model: Payment, name: ModelName }; 25 | -------------------------------------------------------------------------------- /client/src/hooks/useOffSetTop.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function useOffSetTop(top) { 6 | const [offsetTop, setOffSetTop] = useState(false); 7 | const isTop = top || 100; 8 | 9 | useEffect(() => { 10 | window.onscroll = () => { 11 | if (window.pageYOffset > isTop) { 12 | setOffSetTop(true); 13 | } else { 14 | setOffSetTop(false); 15 | } 16 | }; 17 | return () => { 18 | window.onscroll = null; 19 | }; 20 | }, [isTop]); 21 | 22 | return offsetTop; 23 | } 24 | 25 | // Usage 26 | // const offset = useOffSetTop(100); 27 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/general/app/index.js: -------------------------------------------------------------------------------- 1 | export { default as AppWidget } from './AppWidget'; 2 | export { default as AppWelcome } from './AppWelcome'; 3 | export { default as AppFeatured } from './AppFeatured'; 4 | export { default as AppNewInvoice } from './AppNewInvoice'; 5 | export { default as AppTopAuthors } from './AppTopAuthors'; 6 | export { default as AppTopRelated } from './AppTopRelated'; 7 | export { default as AppAreaInstalled } from './AppAreaInstalled'; 8 | export { default as AppWidgetSummary } from './AppWidgetSummary'; 9 | export { default as AppCurrentDownload } from './AppCurrentDownload'; 10 | export { default as AppTopInstalledCountries } from './AppTopInstalledCountries'; 11 | -------------------------------------------------------------------------------- /client/src/components/ThemeLocalization.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // @mui 3 | import { ThemeProvider, createTheme, useTheme } from '@mui/material/styles'; 4 | // hooks 5 | import useLocales from '../hooks/useLocales'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | ThemeLocalization.propTypes = { 10 | children: PropTypes.node, 11 | }; 12 | 13 | export default function ThemeLocalization({ children }) { 14 | const defaultTheme = useTheme(); 15 | const { currentLang } = useLocales(); 16 | 17 | const theme = createTheme(defaultTheme, currentLang.systemValue); 18 | 19 | return {children}; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "demo": { 3 | "title": "German", 4 | "introduction": "Lorem Ipsum ist einfach Dummy-Text der Druck- und Satzindustrie. Lorem Ipsum ist seit dem 16. Jahrhundert der Standard-Dummy-Text der Branche, als ein unbekannter Drucker eine Galeere vom Typ nahm und sie zu einem Musterbuch verschlüsselte. Es hat nicht nur fünf Jahrhunderte überlebt, sondern auch den Sprung in den elektronischen Satz, der im Wesentlichen unverändert geblieben ist. Es wurde in den 1960er Jahren mit der Veröffentlichung von Letraset-Blättern mit Lorem Ipsum-Passagen und in jüngerer Zeit mit Desktop-Publishing-Software wie Aldus PageMaker einschließlich Versionen von Lorem Ipsum populär gemacht." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/local.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Strategy } from 'passport-local'; 2 | import { PassportStrategy } from '@nestjs/passport'; 3 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 4 | import { AuthService } from './auth.service'; 5 | 6 | @Injectable() 7 | export class LocalStrategy extends PassportStrategy(Strategy) { 8 | constructor(private authService: AuthService) { 9 | super(); 10 | } 11 | 12 | async validate(username: string, password: string): Promise { 13 | const user = await this.authService.validateUser(username, password); 14 | if (!user) { 15 | throw new UnauthorizedException(); 16 | } 17 | return user; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/src/modules/user/index.js: -------------------------------------------------------------------------------- 1 | const authRoutes = require("./auth-controller"); 2 | const userRoutes = require("./controller"); 3 | const { 4 | authenticateRequest, 5 | authorizeRequest, 6 | } = require("../../common/middlewares"); 7 | 8 | const { name: ModelName } = require("./model"); 9 | 10 | const processRequest = async (req, res, next) => { 11 | req.modelName = ModelName; 12 | return next(); 13 | }; 14 | 15 | const init = async (app) => { 16 | app.use("/api/auth", authRoutes); 17 | app.use( 18 | "/api/users", 19 | authenticateRequest, 20 | // authorizeRequest, 21 | processRequest, 22 | userRoutes 23 | ); 24 | return app; 25 | }; 26 | 27 | module.exports = { init }; 28 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Progress.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Progress(theme) { 4 | const isLight = theme.palette.mode === 'light'; 5 | 6 | return { 7 | MuiLinearProgress: { 8 | styleOverrides: { 9 | root: { 10 | borderRadius: 4, 11 | overflow: 'hidden', 12 | }, 13 | bar: { 14 | borderRadius: 4, 15 | }, 16 | colorPrimary: { 17 | backgroundColor: theme.palette.primary[isLight ? 'lighter' : 'darker'], 18 | }, 19 | buffer: { 20 | backgroundColor: 'transparent', 21 | }, 22 | }, 23 | }, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /server/src/modules/role/service.js: -------------------------------------------------------------------------------- 1 | const { ObjectId } = require("mongoose").Types; 2 | const { name } = require("./model"); 3 | 4 | const getQuery = (payload) => { 5 | const createdBySubQuery = { createdBy: ObjectId(payload.userId) }; 6 | 7 | let query = createdBySubQuery; 8 | if (payload.name) { 9 | query = { 10 | $and: [ 11 | createdBySubQuery, 12 | { 13 | $or: [ 14 | { name: { $regex: payload.name, $options: "i" } }, 15 | { alias: { $regex: payload.name, $options: "i" } }, 16 | ], 17 | }, 18 | ], 19 | }; 20 | } 21 | return query; 22 | }; 23 | 24 | module.exports = { 25 | getQuery, 26 | modelName: name, 27 | }; 28 | -------------------------------------------------------------------------------- /client/src/utils/formatTime.js: -------------------------------------------------------------------------------- 1 | import { format, getTime, formatDistanceToNow } from 'date-fns'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export function fDate(date) { 6 | return format(new Date(date), 'dd MMMM yyyy'); 7 | } 8 | 9 | export function fDateTime(date) { 10 | return format(new Date(date), 'dd MMM yyyy HH:mm'); 11 | } 12 | 13 | export function fTimestamp(date) { 14 | return getTime(new Date(date)); 15 | } 16 | 17 | export function fDateTimeSuffix(date) { 18 | return format(new Date(date), 'dd/MM/yyyy hh:mm p'); 19 | } 20 | 21 | export function fToNow(date) { 22 | return formatDistanceToNow(new Date(date), { 23 | addSuffix: true 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /server-nest/src/modules/product/product.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { Product, ProductSchema } from './entity/product.entity'; 5 | import { ProductRepository } from './repository/product.repository'; 6 | import { ProductController } from './product.controller'; 7 | import { ProductService } from './product.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([{ name: Product.name, schema: ProductSchema }]), 12 | ], 13 | controllers: [ProductController], 14 | providers: [ProductService, ProductRepository], 15 | exports: [ProductService, ProductRepository], 16 | }) 17 | export class ProductModule {} 18 | -------------------------------------------------------------------------------- /server/src/modules/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | const init = async (app) => { 4 | const rootPath = __dirname; 5 | const moduleNames = await fs.promises.readdir(rootPath); 6 | await Promise.all( 7 | moduleNames.map(async (moduleName) => { 8 | const stat = await fs.promises.lstat(`${rootPath}/${moduleName}`); 9 | if (stat.isDirectory()) { 10 | // eslint-disable-next-line global-require 11 | const module = require(`./${moduleName}`); 12 | if (module.init) { 13 | await module.init(app); 14 | // console.log(`Module ${moduleName} loaded`); 15 | } 16 | } 17 | }) 18 | ); 19 | return app; 20 | }; 21 | 22 | module.exports = { init }; 23 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/general/booking/index.js: -------------------------------------------------------------------------------- 1 | export { default as BookingDetails } from './BookingDetails'; 2 | export { default as BookingBookedRoom } from './BookingBookedRoom'; 3 | export { default as BookingTotalIncomes } from './BookingTotalIncomes'; 4 | export { default as BookingRoomAvailable } from './BookingRoomAvailable'; 5 | export { default as BookingNewestBooking } from './BookingNewestBooking'; 6 | export { default as BookingCheckInWidgets } from './BookingCheckInWidgets'; 7 | export { default as BookingCustomerReviews } from './BookingCustomerReviews'; 8 | export { default as BookingReservationStats } from './BookingReservationStats'; 9 | export { default as BookingWidgetSummary } from './BookingWidgetSummary'; 10 | -------------------------------------------------------------------------------- /client/src/components/animate/variants/transition.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const varTranHover = (props) => { 4 | const duration = props?.duration || 0.32; 5 | const ease = props?.ease || [0.43, 0.13, 0.23, 0.96]; 6 | 7 | return { duration, ease }; 8 | }; 9 | 10 | export const varTranEnter = (props) => { 11 | const duration = props?.durationIn || 0.64; 12 | const ease = props?.easeIn || [0.43, 0.13, 0.23, 0.96]; 13 | 14 | return { duration, ease }; 15 | }; 16 | 17 | export const varTranExit = (props) => { 18 | const duration = props?.durationOut || 0.48; 19 | const ease = props?.easeOut || [0.43, 0.13, 0.23, 0.96]; 20 | 21 | return { duration, ease }; 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/components/hook-form/RHFSwitch.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // form 3 | import { useFormContext, Controller } from 'react-hook-form'; 4 | // @mui 5 | import { Switch, FormControlLabel } from '@mui/material'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | RHFSwitch.propTypes = { 10 | name: PropTypes.string, 11 | }; 12 | 13 | export default function RHFSwitch({ name, ...other }) { 14 | const { control } = useFormContext(); 15 | 16 | return ( 17 | } /> 20 | } 21 | {...other} 22 | /> 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /client/src/components/SvgIconStyle.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Box } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | SvgIconStyle.propTypes = { 7 | src: PropTypes.string.isRequired, 8 | sx: PropTypes.object, 9 | }; 10 | 11 | export default function SvgIconStyle({ src, sx }) { 12 | return ( 13 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/mail/index.js: -------------------------------------------------------------------------------- 1 | export { default as MailCompose } from './MailCompose'; 2 | export { default as MailDetails } from './MailDetails'; 3 | export { default as MailDetailsAttachments } from './MailDetailsAttachments'; 4 | export { default as MailDetailsReplyInput } from './MailDetailsReplyInput'; 5 | export { default as MailDetailsToolbar } from './MailDetailsToolbar'; 6 | export { default as MailList } from './MailList'; 7 | export { default as MailItem } from './MailItem'; 8 | export { default as MailItemAction } from './MailItemAction'; 9 | export { default as MailToolbar } from './MailToolbar'; 10 | export { default as MailSidebar } from './MailSidebar'; 11 | export { default as MailSidebarItem } from './MailSidebarItem'; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sabil", 3 | "version": "1.0.0", 4 | "engines": { 5 | "node": "16.x" 6 | }, 7 | "description": "A functional ecommerce web application that is developed by using React, Redux, Node.js, Express, MongoDB", 8 | "main": "index.js", 9 | "scripts": { 10 | "start": "sudo docker-compose up", 11 | "build": "docker-compose build" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/shakilhasan/sabil.git" 16 | }, 17 | "keywords": [], 18 | "author": "Md.Shakil Hasan Ibn Younus", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/shakilhasan/sabil/issues" 22 | }, 23 | "homepage": "https://github.com/shakilhasan/sabil#readme" 24 | } 25 | -------------------------------------------------------------------------------- /client/src/components/Page.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Helmet } from 'react-helmet-async'; 3 | import { forwardRef } from 'react'; 4 | // @mui 5 | import { Box } from '@mui/material'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | const Page = forwardRef(({ children, title = '', meta, ...other }, ref) => ( 10 | <> 11 | 12 | {`${title} | Minimal-UI`} 13 | {meta} 14 | 15 | 16 | 17 | {children} 18 | 19 | 20 | )); 21 | 22 | Page.propTypes = { 23 | children: PropTypes.node.isRequired, 24 | title: PropTypes.string, 25 | meta: PropTypes.node, 26 | }; 27 | 28 | export default Page; 29 | -------------------------------------------------------------------------------- /server-nest/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/general/e-commerce/index.js: -------------------------------------------------------------------------------- 1 | export { default as EcommerceWelcome } from './EcommerceWelcome'; 2 | export { default as EcommerceNewProducts } from './EcommerceNewProducts'; 3 | export { default as EcommerceYearlySales } from './EcommerceYearlySales'; 4 | export { default as EcommerceBestSalesman } from './EcommerceBestSalesman'; 5 | export { default as EcommerceSaleByGender } from './EcommerceSaleByGender'; 6 | export { default as EcommerceSalesOverview } from './EcommerceSalesOverview'; 7 | export { default as EcommerceWidgetSummary } from './EcommerceWidgetSummary'; 8 | export { default as EcommerceLatestProducts } from './EcommerceLatestProducts'; 9 | export { default as EcommerceCurrentBalance } from './EcommerceCurrentBalance'; 10 | -------------------------------------------------------------------------------- /server/src/modules/permission/request.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const schema = Joi.object().keys({ 4 | _id: Joi.string().optional(), 5 | roleId: Joi.string().required(), 6 | roleName: Joi.string().required(), 7 | roleAlias: Joi.string().required(), 8 | resourceId: Joi.string().required(), 9 | resourceName: Joi.string().required(), 10 | resourceAlias: Joi.string().required(), 11 | isAllowed: Joi.bool().required(), 12 | isDisabled: Joi.bool().required(), 13 | }); 14 | 15 | const validate = (data, user) => { 16 | const result = schema.validate(data); 17 | result.value = { 18 | ...data, 19 | createdBy: user.id, 20 | updatedBy: user.id, 21 | }; 22 | return result; 23 | }; 24 | 25 | module.exports = { validate }; 26 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonPost.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Box, Skeleton } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonPost() { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /client/src/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "demo": { 3 | "title": "France", 4 | "introduction": "Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/general/analytics/index.js: -------------------------------------------------------------------------------- 1 | export { default as AnalyticsTasks } from './AnalyticsTasks'; 2 | export { default as AnalyticsNewsUpdate } from './AnalyticsNewsUpdate'; 3 | export { default as AnalyticsCurrentVisits } from './AnalyticsCurrentVisits'; 4 | export { default as AnalyticsOrderTimeline } from './AnalyticsOrderTimeline'; 5 | export { default as AnalyticsTrafficBySite } from './AnalyticsTrafficBySite'; 6 | export { default as AnalyticsWebsiteVisits } from './AnalyticsWebsiteVisits'; 7 | export { default as AnalyticsWidgetSummary } from './AnalyticsWidgetSummary'; 8 | export { default as AnalyticsCurrentSubject } from './AnalyticsCurrentSubject'; 9 | export { default as AnalyticsConversionRates } from './AnalyticsConversionRates'; 10 | -------------------------------------------------------------------------------- /server-nest/src/modules/customer/customer.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { Customer, CustomerSchema } from './entity/customer.entity'; 5 | import { CustomerRepository } from './repository/customer.repository'; 6 | import { CustomerController } from './customer.controller'; 7 | import { CustomerService } from './customer.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([ 12 | { name: Customer.name, schema: CustomerSchema }, 13 | ]), 14 | ], 15 | controllers: [CustomerController], 16 | providers: [CustomerService, CustomerRepository], 17 | exports: [CustomerService, CustomerRepository], 18 | }) 19 | export class CustomerModule {} 20 | -------------------------------------------------------------------------------- /server-nest/src/modules/resource/resource.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { Resource, ResourceSchema } from './entity/resource.entity'; 5 | import { ResourceRepository } from './repository/resource.repository'; 6 | import { ResourceController } from './resource.controller'; 7 | import { ResourceService } from './resource.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([ 12 | { name: Resource.name, schema: ResourceSchema }, 13 | ]), 14 | ], 15 | controllers: [ResourceController], 16 | providers: [ResourceService, ResourceRepository], 17 | exports: [ResourceService, ResourceRepository], 18 | }) 19 | export class ResourceModule {} 20 | -------------------------------------------------------------------------------- /client/src/components/map/MapControlGeolocate.js: -------------------------------------------------------------------------------- 1 | import { GeolocateControl } from 'react-map-gl'; 2 | // @mui 3 | import { styled } from '@mui/material/styles'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | const GeolocateControlStyle = styled(GeolocateControl)(({ theme }) => ({ 8 | zIndex: 99, 9 | borderRadius: 8, 10 | overflow: 'hidden', 11 | top: theme.spacing(6), 12 | left: theme.spacing(1.5), 13 | boxShadow: theme.customShadows.z8, 14 | })); 15 | 16 | // ---------------------------------------------------------------------- 17 | 18 | export default function MapControlGeolocate({ ...other }) { 19 | return ; 20 | } 21 | -------------------------------------------------------------------------------- /client/src/components/TextIconLabel.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // @mui 3 | import { Stack } from '@mui/material'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | TextIconLabel.propTypes = { 8 | endIcon: PropTypes.bool, 9 | icon: PropTypes.any, 10 | sx: PropTypes.object, 11 | value: PropTypes.any, 12 | }; 13 | 14 | export default function TextIconLabel({ icon, value, endIcon = false, sx, ...other }) { 15 | return ( 16 | 25 | {!endIcon && icon} 26 | {value} 27 | {endIcon && icon} 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /client/src/components/hook-form/RHFTextField.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // form 3 | import { useFormContext, Controller } from 'react-hook-form'; 4 | // @mui 5 | import { TextField } from '@mui/material'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | RHFTextField.propTypes = { 10 | name: PropTypes.string, 11 | }; 12 | 13 | export default function RHFTextField({ name, ...other }) { 14 | const { control } = useFormContext(); 15 | 16 | return ( 17 | ( 21 | 22 | )} 23 | /> 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/blog/index.js: -------------------------------------------------------------------------------- 1 | export { default as BlogNewPostForm } from './BlogNewPostForm'; 2 | export { default as BlogNewPostPreview } from './BlogNewPostPreview'; 3 | export { default as BlogPostCard } from './BlogPostCard'; 4 | export { default as BlogPostCommentForm } from './BlogPostCommentForm'; 5 | export { default as BlogPostCommentItem } from './BlogPostCommentItem'; 6 | export { default as BlogPostCommentList } from './BlogPostCommentList'; 7 | export { default as BlogPostHero } from './BlogPostHero'; 8 | export { default as BlogPostRecent } from './BlogPostRecent'; 9 | export { default as BlogPostsSearch } from './BlogPostsSearch'; 10 | export { default as BlogPostsSort } from './BlogPostsSort'; 11 | export { default as BlogPostTags } from './BlogPostTags'; 12 | -------------------------------------------------------------------------------- /server-nest/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module', 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/entity/locationRelationship.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Entity, 3 | Column, 4 | ManyToOne, 5 | JoinColumn, 6 | PrimaryGeneratedColumn, 7 | } from 'typeorm'; 8 | 9 | import { Location } from './location.entity'; 10 | 11 | @Entity() 12 | export class LocationRelationship { 13 | @PrimaryGeneratedColumn() 14 | id: number; 15 | 16 | @ManyToOne(() => Location, (location) => location.ancestor_relationships) 17 | @JoinColumn({ name: 'ancestor_id', referencedColumnName: 'id' }) 18 | ancestor: Location; 19 | 20 | @ManyToOne(() => Location, (location) => location.descendant_relationships) 21 | @JoinColumn({ name: 'descendant_id', referencedColumnName: 'id' }) 22 | descendant: Location; 23 | 24 | @Column() 25 | distance: number; 26 | } 27 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/e-commerce/checkout/index.js: -------------------------------------------------------------------------------- 1 | export { default as CheckoutBillingAddress } from './CheckoutBillingAddress'; 2 | export { default as CheckoutBillingInfo } from './CheckoutBillingInfo'; 3 | export { default as CheckoutCart } from './CheckoutCart'; 4 | export { default as CheckoutDelivery } from './CheckoutDelivery'; 5 | export { default as CheckoutNewAddressForm } from './CheckoutNewAddressForm'; 6 | export { default as CheckoutOrderComplete } from './CheckoutOrderComplete'; 7 | export { default as CheckoutPayment } from './CheckoutPayment'; 8 | export { default as CheckoutPaymentMethods } from './CheckoutPaymentMethods'; 9 | export { default as CheckoutProductList } from './CheckoutProductList'; 10 | export { default as CheckoutSummary } from './CheckoutSummary'; 11 | -------------------------------------------------------------------------------- /client/public/icons/ic_github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Slider.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Slider(theme) { 4 | const isLight = theme.palette.mode === 'light'; 5 | 6 | return { 7 | MuiSlider: { 8 | defaultProps: { 9 | size: 'small', 10 | }, 11 | 12 | styleOverrides: { 13 | root: { 14 | '&.Mui-disabled': { 15 | color: theme.palette.action.disabled, 16 | }, 17 | }, 18 | markLabel: { 19 | fontSize: 13, 20 | color: theme.palette.text.disabled, 21 | }, 22 | valueLabel: { 23 | borderRadius: 8, 24 | backgroundColor: theme.palette.grey[isLight ? 800 : 700], 25 | }, 26 | }, 27 | }, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /client/src/components/map/MapControlFullscreen.js: -------------------------------------------------------------------------------- 1 | import { FullscreenControl } from 'react-map-gl'; 2 | // @mui 3 | import { styled } from '@mui/material/styles'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | const FullscreenControlStyle = styled(FullscreenControl)(({ theme }) => ({ 8 | zIndex: 99, 9 | borderRadius: 8, 10 | overflow: 'hidden', 11 | top: theme.spacing(1.5), 12 | left: theme.spacing(1.5), 13 | boxShadow: theme.customShadows.z8, 14 | '& span.mapboxgl-ctrl-icon': { 15 | transform: ' scale(0.75)', 16 | }, 17 | })); 18 | 19 | // ---------------------------------------------------------------------- 20 | 21 | export default function MapControlFullscreen({ ...other }) { 22 | return ; 23 | } 24 | -------------------------------------------------------------------------------- /server-nest/src/modules/permission/permission.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | 4 | import { Permission, PermissionSchema } from './entity/permission.entity'; 5 | import { PermissionRepository } from './repository/permission.repository'; 6 | import { PermissionController } from './permission.controller'; 7 | import { PermissionService } from './permission.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([ 12 | { name: Permission.name, schema: PermissionSchema }, 13 | ]), 14 | ], 15 | controllers: [PermissionController], 16 | providers: [PermissionService, PermissionRepository], 17 | exports: [PermissionService, PermissionRepository], 18 | }) 19 | export class PermissionModule {} 20 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/blog/BlogPostsSort.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // @mui 3 | import { MenuItem, TextField } from '@mui/material'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | BlogPostsSort.propTypes = { 8 | query: PropTypes.string, 9 | options: PropTypes.array, 10 | onSort: PropTypes.func, 11 | }; 12 | 13 | export default function BlogPostsSort({ query, options, onSort }) { 14 | return ( 15 | onSort(e.target.value)}> 16 | {options.map((option) => ( 17 | 18 | {option.label} 19 | 20 | ))} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /client/src/components/map/MapControlNavigation.js: -------------------------------------------------------------------------------- 1 | import { NavigationControl } from 'react-map-gl'; 2 | // @mui 3 | import { styled } from '@mui/material/styles'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | const NavigationControlStyle = styled(NavigationControl)(({ theme }) => ({ 8 | zIndex: 99, 9 | borderRadius: 8, 10 | overflow: 'hidden', 11 | bottom: theme.spacing(6), 12 | left: theme.spacing(1.5), 13 | boxShadow: theme.customShadows.z8, 14 | '& button+button': { 15 | borderTop: `1px solid ${theme.palette.divider}`, 16 | }, 17 | })); 18 | 19 | // ---------------------------------------------------------------------- 20 | 21 | export default function MapControlNavigation({ ...other }) { 22 | return ; 23 | } 24 | -------------------------------------------------------------------------------- /server/src/common/utils.js: -------------------------------------------------------------------------------- 1 | const listEndpoints = require("express-list-endpoints"); 2 | // const mongoose = require("mongoose"); 3 | const { Model: Resource } = require("../modules/resource/model"); 4 | 5 | const generateResource = async (app) => { 6 | const endpoints = listEndpoints(app); 7 | const resources = endpoints.map((d) => ({ 8 | name: d.path, 9 | alias: `${d.path.split("/")?.[2] ?? ""}-${d.path.split("/")?.[3] ?? ""}`, 10 | type: "api", 11 | })); 12 | 13 | // const resource = await mongoose.models["Resource"].insertMany(all); 14 | try { 15 | const resource = await Resource.insertMany(resources); 16 | console.log("resource--", resource); 17 | } catch (error) { 18 | console.log("error--", error); 19 | } 20 | }; 21 | module.exports = { 22 | generateResource, 23 | }; 24 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Avatar.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Avatar(theme) { 4 | return { 5 | MuiAvatar: { 6 | styleOverrides: { 7 | colorDefault: { 8 | color: theme.palette.text.secondary, 9 | backgroundColor: theme.palette.grey[400], 10 | }, 11 | }, 12 | }, 13 | MuiAvatarGroup: { 14 | styleOverrides: { 15 | avatar: { 16 | fontSize: 16, 17 | fontWeight: theme.typography.fontWeightMedium, 18 | '&:first-of-type': { 19 | fontSize: 14, 20 | color: theme.palette.primary.main, 21 | backgroundColor: theme.palette.primary.lighter, 22 | }, 23 | }, 24 | }, 25 | }, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/theme/overrides/TreeView.js: -------------------------------------------------------------------------------- 1 | import { TreeViewCollapseIcon, TreeViewExpandIcon, TreeViewEndIcon } from './CustomIcons'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function TreeView(theme) { 6 | return { 7 | MuiTreeView: { 8 | defaultProps: { 9 | defaultCollapseIcon: , 10 | defaultExpandIcon: , 11 | defaultEndIcon: , 12 | }, 13 | }, 14 | MuiTreeItem: { 15 | styleOverrides: { 16 | label: { ...theme.typography.body2 }, 17 | iconContainer: { width: 'auto' }, 18 | }, 19 | }, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /client/public/icons/ic_kanban.svg: -------------------------------------------------------------------------------- 1 | ic_kanban -------------------------------------------------------------------------------- /client/src/theme/overrides/Drawer.js: -------------------------------------------------------------------------------- 1 | import { alpha } from '@mui/material'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function Drawer(theme) { 6 | const isLight = theme.palette.mode === 'light'; 7 | 8 | return { 9 | MuiDrawer: { 10 | styleOverrides: { 11 | modal: { 12 | '&[role="presentation"]': { 13 | '& .MuiDrawer-paperAnchorLeft': { 14 | boxShadow: `8px 24px 24px 12px ${alpha(theme.palette.grey[900], isLight ? 0.16 : 0.48)}`, 15 | }, 16 | '& .MuiDrawer-paperAnchorRight': { 17 | boxShadow: `-8px 24px 24px 12px ${alpha(theme.palette.grey[900], isLight ? 0.16 : 0.48)}`, 18 | }, 19 | }, 20 | }, 21 | }, 22 | }, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonProduct.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Grid, Skeleton } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonProduct() { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Rating.js: -------------------------------------------------------------------------------- 1 | // 2 | import { StarIcon } from './CustomIcons'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | const ICON_SMALL = { width: 20, height: 20 }; 7 | const ICON_LARGE = { width: 28, height: 28 }; 8 | 9 | export default function Rating(theme) { 10 | return { 11 | MuiRating: { 12 | defaultProps: { 13 | emptyIcon: , 14 | icon: , 15 | }, 16 | 17 | styleOverrides: { 18 | root: { 19 | '&.Mui-disabled': { 20 | opacity: 0.48, 21 | }, 22 | }, 23 | iconEmpty: { color: theme.palette.grey[500_48] }, 24 | sizeSmall: { '& svg': { ...ICON_SMALL } }, 25 | sizeLarge: { '& svg': { ...ICON_LARGE } }, 26 | }, 27 | }, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/user/profile/index.js: -------------------------------------------------------------------------------- 1 | export { default as Profile } from './Profile'; 2 | export { default as ProfileCover } from './ProfileCover'; 3 | export { default as ProfileFriends } from './ProfileFriends'; 4 | export { default as ProfileGallery } from './ProfileGallery'; 5 | export { default as ProfilePostCard } from './ProfilePostCard'; 6 | export { default as ProfileAbout } from './ProfileAbout'; 7 | export { default as ProfileFollowers } from './ProfileFollowers'; 8 | export { default as ProfileFollowings } from './ProfileFollowings'; 9 | export { default as ProfileUsers } from './ProfileUsers'; 10 | export { default as ProfileFollowInfo } from './ProfileFollowInfo'; 11 | export { default as ProfileSocialInfo } from './ProfileSocialInfo'; 12 | export { default as ProfilePostProfileInput } from './ProfilePostInput'; 13 | -------------------------------------------------------------------------------- /client/src/utils/getColorName.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function getColorName(hex) { 4 | let color; 5 | 6 | switch (hex) { 7 | case '#00AB55': 8 | color = 'Green'; 9 | break; 10 | case '#000000': 11 | color = 'Black'; 12 | break; 13 | case '#FFFFFF': 14 | color = 'White'; 15 | break; 16 | case '#FFC0CB': 17 | color = 'Pink'; 18 | break; 19 | case '#FF4842': 20 | color = 'Red'; 21 | break; 22 | case '#1890FF': 23 | color = 'Blue'; 24 | break; 25 | case '#94D82D': 26 | color = 'Greenyellow'; 27 | break; 28 | case '#FFC107': 29 | color = 'Orange'; 30 | break; 31 | default: 32 | color = hex; 33 | } 34 | 35 | return color; 36 | } 37 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/blog/BlogPostRecent.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // @mui 3 | import { Grid, Typography } from '@mui/material'; 4 | // 5 | import BlogPostCard from './BlogPostCard'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | BlogPostRecent.propTypes = { 10 | posts: PropTypes.array.isRequired, 11 | }; 12 | 13 | export default function BlogPostRecent({ posts }) { 14 | return ( 15 | <> 16 | 17 | Recent posts 18 | 19 | 20 | 21 | {posts.map((post) => ( 22 | 23 | 24 | 25 | ))} 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /client/.env.sample: -------------------------------------------------------------------------------- 1 | # FIX REFRESH "react-scripts": "4.x" 2 | # https://github.com/facebook/create-react-app/issues/9984 3 | FAST_REFRESH=false 4 | 5 | PORT=8001 6 | 7 | REACT_APP_HOST_API_KEY=https://minimal-assets-api.vercel.app 8 | #REACT_APP_HOST_API_KEY=http://localhost:8080 9 | REACT_APP_API_URL=http://localhost:8080/api 10 | # MAP 11 | REACT_APP_MAPBOX= 12 | 13 | # FIREBASE 14 | REACT_APP_FIREBASE_API_KEY= 15 | REACT_APP_FIREBASE_AUTH_DOMAIN= 16 | REACT_APP_FIREBASE_PROJECT_ID= 17 | REACT_APP_FIREBASE_STORAGE_BUCKET= 18 | REACT_APP_FIREBASE_MESSAGING_SENDER_ID= 19 | REACT_APP_FIREBASE_APPID= 20 | REACT_APP_FIREBASE_MEASUREMENT_ID= 21 | 22 | # AWS COGNITO 23 | REACT_APP_AWS_COGNITO_USER_POOL_ID= 24 | REACT_APP_AWS_COGNITO_CLIENT_ID= 25 | 26 | # AUTH0 27 | REACT_APP_AUTH0_DOMAIN= 28 | REACT_APP_AUTH0_CLIENT_ID= 29 | 30 | SKIP_PREFLIGHT_CHECK=true 31 | -------------------------------------------------------------------------------- /server-nest/src/modules/permission/dto/createPermission.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | import { Prop } from '@nestjs/mongoose'; 4 | import { User } from '../../user/entity/user.entity'; 5 | export class CreatePermissionDto { 6 | @IsOptional() id: MongooseSchema.Types.ObjectId; 7 | @IsOptional() roleId: MongooseSchema.Types.ObjectId; 8 | @IsOptional() roleName: string; 9 | @IsOptional() roleAlias: string; 10 | @IsOptional() resourceId: MongooseSchema.Types.ObjectId; 11 | @IsOptional() resourceName: string; 12 | @IsOptional() resourceAlias: string; 13 | @IsOptional() isAllowed: boolean; 14 | @IsOptional() isDisabled: boolean; 15 | @IsOptional() createdBy: MongooseSchema.Types.ObjectId; 16 | @IsOptional() updatedBy: MongooseSchema.Types.ObjectId; 17 | } 18 | -------------------------------------------------------------------------------- /client/public/icons/ic_dashboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/layouts/LogoOnlyLayout.js: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom'; 2 | // @mui 3 | import { styled } from '@mui/material/styles'; 4 | // components 5 | import Logo from '../components/Logo'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | const HeaderStyle = styled('header')(({ theme }) => ({ 10 | top: 0, 11 | left: 0, 12 | lineHeight: 0, 13 | width: '100%', 14 | position: 'absolute', 15 | padding: theme.spacing(3, 3, 0), 16 | [theme.breakpoints.up('sm')]: { 17 | padding: theme.spacing(5, 5, 0) 18 | } 19 | })); 20 | 21 | // ---------------------------------------------------------------------- 22 | 23 | export default function LogoOnlyLayout() { 24 | return ( 25 | <> 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /server/src/core/logger.js: -------------------------------------------------------------------------------- 1 | const winston = require("winston"); 2 | 3 | const alignColorsAndTime = winston.format.combine( 4 | winston.format.colorize({ 5 | all: true, 6 | }), 7 | winston.format.label({ 8 | label: "[LOGGER]", 9 | }), 10 | winston.format.printf( 11 | (info) => ` ${info.label}-[${info.level}] : ${info.message}` 12 | ) 13 | ); 14 | 15 | const winstonLogger = winston.createLogger({ 16 | level: "debug", 17 | transports: [ 18 | new winston.transports.Console({ 19 | format: winston.format.combine( 20 | winston.format.colorize(), 21 | alignColorsAndTime 22 | ), 23 | }), 24 | ], 25 | }); 26 | 27 | const pinoLogger = require("pino")(); 28 | 29 | const logOption = process.env.logger || "winston"; 30 | 31 | if (logOption === "pino") module.exports = pinoLogger; 32 | else module.exports = winstonLogger; 33 | -------------------------------------------------------------------------------- /client/src/theme/overrides/List.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function List(theme) { 4 | return { 5 | MuiListItemIcon: { 6 | styleOverrides: { 7 | root: { 8 | color: 'inherit', 9 | minWidth: 'auto', 10 | marginRight: theme.spacing(2), 11 | }, 12 | }, 13 | }, 14 | MuiListItemAvatar: { 15 | styleOverrides: { 16 | root: { 17 | minWidth: 'auto', 18 | marginRight: theme.spacing(2), 19 | }, 20 | }, 21 | }, 22 | MuiListItemText: { 23 | styleOverrides: { 24 | root: { 25 | marginTop: 0, 26 | marginBottom: 0, 27 | }, 28 | multiline: { 29 | marginTop: 0, 30 | marginBottom: 0, 31 | }, 32 | }, 33 | }, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /server-nest/src/modules/blog/dto/createBlog.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | import { Prop } from '@nestjs/mongoose'; 4 | import { User } from '../../user/entity/user.entity'; 5 | 6 | export class CreateBlogDto { 7 | @IsOptional() id: MongooseSchema.Types.ObjectId; 8 | @IsOptional() cover: string; 9 | @IsOptional() title: string; 10 | @IsOptional() description: string; 11 | @IsOptional() view: number; 12 | @IsOptional() comment: number; 13 | @IsOptional() share: number; 14 | @IsOptional() favorite: number; 15 | @IsOptional() author: any; 16 | @IsOptional() authorId: MongooseSchema.Types.ObjectId; 17 | @IsOptional() avatarUrl: string; 18 | @IsOptional() tags: []; 19 | @IsOptional() body: string; 20 | @IsOptional() favoritePerson: any; 21 | @IsOptional() comments: any; 22 | } 23 | -------------------------------------------------------------------------------- /client/src/components/SearchNotFound.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Paper, Typography } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | SearchNotFound.propTypes = { 7 | searchQuery: PropTypes.string, 8 | }; 9 | 10 | export default function SearchNotFound({ searchQuery = '', ...other }) { 11 | return searchQuery ? ( 12 | 13 | 14 | Not found 15 | 16 | 17 | No results found for   18 | "{searchQuery}". Try checking for typos or using complete words. 19 | 20 | 21 | ) : ( 22 | Please enter keywords 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Backdrop.js: -------------------------------------------------------------------------------- 1 | import { alpha } from '@mui/material/styles'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function Backdrop(theme) { 6 | const varLow = alpha(theme.palette.grey[900], 0.48); 7 | const varHigh = alpha(theme.palette.grey[900], 1); 8 | 9 | return { 10 | MuiBackdrop: { 11 | styleOverrides: { 12 | root: { 13 | background: [ 14 | `rgb(22,28,36)`, 15 | `-moz-linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`, 16 | `-webkit-linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`, 17 | `linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`, 18 | ], 19 | '&.MuiBackdrop-invisible': { 20 | background: 'transparent', 21 | }, 22 | }, 23 | }, 24 | }, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/entity/location.entity.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm'; 2 | 3 | import { LocationRelationship } from './locationRelationship.entity'; 4 | 5 | @Entity() 6 | export class Location { 7 | @PrimaryGeneratedColumn() 8 | id: number; 9 | 10 | @Column() 11 | building: string; 12 | 13 | @Column() 14 | location_name: string; 15 | 16 | @Column() 17 | location_number: string; 18 | 19 | @Column() 20 | area: string; 21 | 22 | @OneToMany( 23 | () => LocationRelationship, 24 | (locationRelationship) => locationRelationship.ancestor, 25 | ) 26 | ancestor_relationships: LocationRelationship[]; 27 | 28 | @OneToMany( 29 | () => LocationRelationship, 30 | (locationRelationship) => locationRelationship.descendant, 31 | ) 32 | descendant_relationships: LocationRelationship[]; 33 | } 34 | -------------------------------------------------------------------------------- /client/src/guards/RoleGuard.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Container, Alert, AlertTitle } from '@mui/material'; 3 | import {useLocation} from "react-router-dom"; 4 | import {checkPermissionAccess} from "../helpers/checkPermission"; 5 | 6 | // ---------------------------------------------------------------------- 7 | RoleGuard.propTypes = { 8 | children: PropTypes.node 9 | }; 10 | 11 | export default function RoleGuard({ children }) { 12 | const { pathname } = useLocation(); 13 | console.log("RoleGuard path:-",pathname) 14 | if (!checkPermissionAccess(pathname)) { 15 | return ( 16 | 17 | 18 | Permission Denied 19 | You do not have permission to access this page 20 | 21 | 22 | ); 23 | } 24 | 25 | return <>{children}; 26 | } 27 | -------------------------------------------------------------------------------- /client/src/sections/map/index.js: -------------------------------------------------------------------------------- 1 | export { default as MapGeojson } from './geojson'; 2 | export { default as MapHeatmap } from './heatmap'; 3 | export { default as MapInteraction } from './interaction'; 4 | export { default as MapChangeTheme } from './change-theme'; 5 | export { default as MapDynamicStyling } from './dynamic-styling'; 6 | export { default as MapDraggableMarkers } from './draggable-markers'; 7 | export { default as MapViewportAnimation } from './viewport-animation'; 8 | 9 | export { default as MapClusters } from './MapClusters'; 10 | export { default as MapZoomToBounds } from './MapZoomToBounds'; 11 | export { default as MapDeckglOverlay } from './MapDeckglOverlay'; 12 | export { default as MapMarkersPopups } from './MapMarkersPopups'; 13 | export { default as MapGeoJSONAnimation } from './MapGeoJSONAnimation'; 14 | export { default as MapHighlightByFilter } from './MapHighlightByFilter'; 15 | -------------------------------------------------------------------------------- /server/src/core/mongo.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | require("dotenv").config(); 3 | 4 | 5 | const isMongoDbUrl = JSON.parse( 6 | process.env.IS_MONGODB_CLOUD_URL ? process.env.IS_MONGODB_CLOUD_URL : "false" 7 | ); 8 | const uri = isMongoDbUrl 9 | ? process.env.MONGODB_CLOUD_URL 10 | : `mongodb://${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`; 11 | 12 | const options = { 13 | useNewUrlParser: true, 14 | useUnifiedTopology: true, 15 | useCreateIndex: true, 16 | }; 17 | const connectWithDb = async (cb, em) => { 18 | const connectionResult = await mongoose.connect(uri, options); 19 | // eslint-disable-next-line no-console 20 | console.log( 21 | `Connected to mongoDB on database: 22 | ${connectionResult.connections[0].name} at ${new Date().toDateString()}` 23 | ); 24 | if (cb && em) cb(em); 25 | }; 26 | module.exports = connectWithDb; 27 | -------------------------------------------------------------------------------- /client/src/locales/i18n.js: -------------------------------------------------------------------------------- 1 | import i18n from 'i18next'; 2 | import { initReactI18next } from 'react-i18next'; 3 | import LanguageDetector from 'i18next-browser-languagedetector'; 4 | // 5 | import enLocales from './en.json'; 6 | import deLocales from './de.json'; 7 | import frLocales from './fr.json'; 8 | 9 | // ---------------------------------------------------------------------- 10 | 11 | i18n 12 | .use(LanguageDetector) 13 | .use(initReactI18next) 14 | .init({ 15 | resources: { 16 | en: { translations: enLocales }, 17 | de: { translations: deLocales }, 18 | fr: { translations: frLocales } 19 | }, 20 | lng: localStorage.getItem('i18nextLng') || 'en', 21 | fallbackLng: 'en', 22 | debug: false, 23 | ns: ['translations'], 24 | defaultNS: 'translations', 25 | interpolation: { 26 | escapeValue: false 27 | } 28 | }); 29 | 30 | export default i18n; 31 | -------------------------------------------------------------------------------- /client/src/redux/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | import { useDispatch as useAppDispatch, useSelector as useAppSelector } from 'react-redux'; 3 | import { persistStore, persistReducer } from 'redux-persist'; 4 | import { rootPersistConfig, rootReducer } from './rootReducer'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | const store = configureStore({ 9 | reducer: persistReducer(rootPersistConfig, rootReducer), 10 | middleware: (getDefaultMiddleware) => 11 | getDefaultMiddleware({ 12 | serializableCheck: false, 13 | immutableCheck: false, 14 | }), 15 | }); 16 | 17 | const persistor = persistStore(store); 18 | 19 | const { dispatch } = store; 20 | 21 | const useSelector = useAppSelector; 22 | 23 | const useDispatch = () => useAppDispatch(); 24 | 25 | export { store, persistor, dispatch, useSelector, useDispatch }; 26 | -------------------------------------------------------------------------------- /client/src/components/animate/variants/rotate.js: -------------------------------------------------------------------------------- 1 | // 2 | import { varTranEnter, varTranExit } from './transition'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export const varRotate = (props) => { 7 | const durationIn = props?.durationIn; 8 | const durationOut = props?.durationOut; 9 | const easeIn = props?.easeIn; 10 | const easeOut = props?.easeOut; 11 | 12 | return { 13 | // IN 14 | in: { 15 | initial: { opacity: 0, rotate: -360 }, 16 | animate: { opacity: 1, rotate: 0, transition: varTranEnter({ durationIn, easeIn }) }, 17 | exit: { opacity: 0, rotate: -360, transition: varTranExit({ durationOut, easeOut }) } 18 | }, 19 | 20 | // OUT 21 | out: { 22 | initial: { opacity: 1, rotate: 0 }, 23 | animate: { opacity: 0, rotate: -360, transition: varTranExit({ durationOut, easeOut }) } 24 | } 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /server/src/modules/customer/service.js: -------------------------------------------------------------------------------- 1 | // load repository.js functions 2 | const { save, update, getById, deleteById } = require("../../core/repository"); 3 | const eventEmitter = require("../../core/event-manager").getInstance(); 4 | 5 | const modelName = "Customer"; 6 | 7 | const setupEventListeners = () => { 8 | eventEmitter.on(`${modelName}Created`, (model) => { 9 | // eslint-disable-next-line no-console 10 | console.log(`${modelName} created`, model); 11 | }); 12 | 13 | eventEmitter.on(`${modelName}Updated`, (model) => { 14 | // eslint-disable-next-line no-console 15 | console.log(`${modelName} updated`, model); 16 | }); 17 | 18 | eventEmitter.on(`${modelName}Deleted`, (model) => { 19 | // eslint-disable-next-line no-console 20 | console.log(`${modelName} deleted`, model); 21 | }); 22 | }; 23 | 24 | setupEventListeners(); 25 | 26 | module.exports = { save, update, deleteById, getById }; 27 | -------------------------------------------------------------------------------- /server/src/modules/salesOrder/productSchema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const productSchema = new mongoose.Schema({ 4 | _id: { type: mongoose.Types.ObjectId }, 5 | 6 | product_id: { type: String, required: false }, 7 | name: { 8 | label:{ type: String, required: false }, 9 | value : {type : String, required:false} 10 | }, 11 | account: { 12 | label:{ type: String, required: false }, 13 | value : {type : String, required:false} 14 | }, 15 | tax: { 16 | label:{ type: String, required: false }, 17 | value : {type : String, required:false} 18 | }, 19 | quantity: { type: String, required: false }, 20 | rate: { type: String, required: false }, 21 | unit: {type: mongoose.Schema.Types.Mixed, require: false, default: null}, 22 | amount: { type: Number, required: false }, 23 | 24 | }); 25 | 26 | 27 | module.exports = productSchema; 28 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/guards/role.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; 2 | import { Reflector } from '@nestjs/core'; 3 | import { RoleEnum } from '../role.enum'; 4 | import { ROLES_KEY } from '../roles.decorator'; 5 | 6 | @Injectable() 7 | export class RolesGuard implements CanActivate { 8 | constructor(private reflector: Reflector) {} 9 | 10 | canActivate(context: ExecutionContext): boolean { 11 | const requiredRoles = this.reflector.getAllAndOverride( 12 | ROLES_KEY, 13 | [context.getHandler(), context.getClass()], 14 | ); 15 | if (!requiredRoles) { 16 | return true; 17 | } 18 | const { user } = context.switchToHttp().getRequest(); 19 | console.log('RolesGuard user----', user); 20 | return requiredRoles.some((role) => user.roleAlias === role); 21 | // return requiredRoles.some((role) => user.roles?.includes(role)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/setup/products.js: -------------------------------------------------------------------------------- 1 | const { save } = require("../src/core/repository"); 2 | const { name: ModelName } = require("../src/modules/product/model"); 3 | const { 4 | getFakeProduct, 5 | } = require("../test/mock-routes/product-controller-mock"); 6 | 7 | const seed = async (logger) => { 8 | const products = []; 9 | logger.info(`Seeding products`); 10 | 11 | // eslint-disable-next-line func-names 12 | await (async function () { 13 | for (let i = 0; i < 40; i++) { 14 | // eslint-disable-next-line no-await-in-loop 15 | const product = await getFakeProduct(); 16 | products.push(product); 17 | } 18 | })(); 19 | 20 | await Promise.all( 21 | products.map(async (product) => { 22 | const savedProduct = await save(product, ModelName); 23 | logger.info(`Saved product id: ${savedProduct._id}`); 24 | }) 25 | ); 26 | logger.info("Seeding products completed"); 27 | }; 28 | 29 | module.exports = { seed }; 30 | -------------------------------------------------------------------------------- /client/src/components/RtlLayout.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect } from 'react'; 3 | // rtl 4 | import rtlPlugin from 'stylis-plugin-rtl'; 5 | // emotion 6 | import createCache from '@emotion/cache'; 7 | import { CacheProvider } from '@emotion/react'; 8 | // @mui 9 | import { useTheme } from '@mui/material/styles'; 10 | 11 | // ---------------------------------------------------------------------- 12 | 13 | RtlLayout.propTypes = { 14 | children: PropTypes.node, 15 | }; 16 | 17 | export default function RtlLayout({ children }) { 18 | const theme = useTheme(); 19 | 20 | useEffect(() => { 21 | document.dir = theme.direction; 22 | }, [theme.direction]); 23 | 24 | const cacheRtl = createCache({ 25 | key: theme.direction === 'rtl' ? 'rtl' : 'css', 26 | stylisPlugins: theme.direction === 'rtl' ? [rtlPlugin] : [], 27 | }); 28 | 29 | return {children}; 30 | } 31 | -------------------------------------------------------------------------------- /client/src/hooks/useResponsive.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { useTheme } from '@mui/material/styles'; 3 | import useMediaQuery from '@mui/material/useMediaQuery'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | export default function useResponsive(query, key, start, end) { 8 | const theme = useTheme(); 9 | 10 | const mediaUp = useMediaQuery(theme.breakpoints.up(key)); 11 | 12 | const mediaDown = useMediaQuery(theme.breakpoints.down(key)); 13 | 14 | const mediaBetween = useMediaQuery(theme.breakpoints.between(start, end)); 15 | 16 | const mediaOnly = useMediaQuery(theme.breakpoints.only(key)); 17 | 18 | if (query === 'up') { 19 | return mediaUp; 20 | } 21 | 22 | if (query === 'down') { 23 | return mediaDown; 24 | } 25 | 26 | if (query === 'between') { 27 | return mediaBetween; 28 | } 29 | 30 | if (query === 'only') { 31 | return mediaOnly; 32 | } 33 | return null; 34 | } 35 | -------------------------------------------------------------------------------- /server-nest/src/modules/customer/entity/customer.entity.ts: -------------------------------------------------------------------------------- 1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; 2 | import { Document } from 'mongoose'; 3 | 4 | @Schema() 5 | export class Customer extends Document { 6 | @Prop({ type: String, required: false }) firstName: string; 7 | @Prop({ type: String, required: false }) lastName: string; 8 | @Prop({ type: String, required: false }) city: string; 9 | @Prop({ type: String, required: false }) state: string; 10 | @Prop({ type: String, required: false }) zip: string; 11 | @Prop({ type: String, required: false, unique: true }) phone: string; 12 | @Prop({ type: String, required: false, unique: true }) email: string; 13 | @Prop({ type: String, required: false }) ip: string; 14 | @Prop({ type: Date, default: Date.now }) updatedAt: Date; 15 | @Prop({ type: Date, default: Date.now }) createdAt: Date; 16 | } 17 | 18 | export const CustomerSchema = SchemaFactory.createForClass(Customer); 19 | -------------------------------------------------------------------------------- /client/src/sections/faqs/FaqsList.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Accordion, Typography, AccordionSummary, AccordionDetails } from '@mui/material'; 3 | // _mock_ 4 | import { _faqs } from '../../_mock'; 5 | // components 6 | import Iconify from '../../components/Iconify'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | export default function FaqsList() { 11 | return ( 12 | <> 13 | {_faqs.map((accordion) => ( 14 | 15 | } 17 | > 18 | {accordion.heading} 19 | 20 | 21 | {accordion.detail} 22 | 23 | 24 | ))} 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /client/src/components/animate/TextAnimate.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { m } from 'framer-motion'; 3 | // @mui 4 | import { Box } from '@mui/material'; 5 | // 6 | import { varFade } from './variants'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | TextAnimate.propTypes = { 11 | text: PropTypes.string.isRequired, 12 | variants: PropTypes.object, 13 | sx: PropTypes.object 14 | }; 15 | 16 | export default function TextAnimate({ text, variants, sx, ...other }) { 17 | return ( 18 | 28 | {text.split('').map((letter, index) => ( 29 | 30 | {letter} 31 | 32 | ))} 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonProductItem.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Card, Skeleton, Stack } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonProductItem() { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /client/src/guards/RoleBasedGuard.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Container, Alert, AlertTitle } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | RoleBasedGuard.propTypes = { 7 | accessibleRoles: PropTypes.array, // Example ['admin', 'leader'] 8 | children: PropTypes.node 9 | }; 10 | 11 | const useCurrentRole = () => { 12 | // Logic here to get current user role 13 | const role = 'admin'; 14 | return role; 15 | }; 16 | 17 | export default function RoleBasedGuard({ accessibleRoles, children }) { 18 | const currentRole = useCurrentRole(); 19 | 20 | if (!accessibleRoles.includes(currentRole)) { 21 | return ( 22 | 23 | 24 | Permission Denied 25 | You do not have permission to access this page 26 | 27 | 28 | ); 29 | } 30 | 31 | return <>{children}; 32 | } 33 | -------------------------------------------------------------------------------- /client/public/icons/ic_chat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-nest/src/modules/product/dto/createProduct.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional } from 'class-validator'; 2 | import { Schema as MongooseSchema } from 'mongoose'; 3 | import { User } from '../../user/entity/user.entity'; 4 | 5 | export class CreateProductDto { 6 | @IsOptional() 7 | id: MongooseSchema.Types.ObjectId; 8 | 9 | @IsOptional() 10 | cover: string; 11 | 12 | @IsOptional() 13 | title: string; 14 | 15 | @IsOptional() 16 | description: string; 17 | 18 | @IsOptional() 19 | view: number; 20 | 21 | @IsOptional() 22 | comment: number; 23 | 24 | @IsOptional() 25 | share: number; 26 | 27 | @IsOptional() 28 | favorite: number; 29 | 30 | @IsOptional() 31 | author: any; 32 | 33 | @IsOptional() 34 | authorId: User; 35 | 36 | @IsOptional() 37 | avatarUrl: string; 38 | 39 | @IsOptional() 40 | tags: []; 41 | 42 | @IsOptional() 43 | body: string; 44 | 45 | @IsOptional() 46 | favoritePerson: any; 47 | 48 | @IsOptional() 49 | comments: any; 50 | } 51 | -------------------------------------------------------------------------------- /server/src/common/errors.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable class-methods-use-this */ 2 | // eslint-disable-next-line max-classes-per-file 3 | class GeneralError extends Error { 4 | constructor(message) { 5 | super(); 6 | this.message = message; 7 | } 8 | 9 | getCode() { 10 | return 400; 11 | } 12 | } 13 | 14 | class BadRequest extends GeneralError { 15 | constructor(message) { 16 | super(message); 17 | this.name = "BadRequest"; 18 | } 19 | 20 | getCode() { 21 | return 400; 22 | } 23 | } 24 | 25 | class NotFound extends GeneralError { 26 | constructor(message) { 27 | super(message); 28 | this.name = "NotFound"; 29 | } 30 | 31 | getCode() { 32 | return 404; 33 | } 34 | } 35 | 36 | class MongoError extends GeneralError { 37 | constructor(message) { 38 | super(message); 39 | this.name = "MongoError"; 40 | } 41 | 42 | getCode() { 43 | return 400; 44 | } 45 | } 46 | 47 | module.exports = { GeneralError, BadRequest, NotFound, MongoError }; 48 | -------------------------------------------------------------------------------- /client/src/components/hook-form/RHFSelect.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // form 3 | import { useFormContext, Controller } from 'react-hook-form'; 4 | // @mui 5 | import { TextField } from '@mui/material'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | RHFSelect.propTypes = { 10 | children: PropTypes.node, 11 | name: PropTypes.string, 12 | }; 13 | 14 | export default function RHFSelect({ name, children, ...other }) { 15 | const { control } = useFormContext(); 16 | 17 | return ( 18 | ( 22 | 31 | {children} 32 | 33 | )} 34 | /> 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /server/src/modules/resource/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | // schema 4 | const schema = new mongoose.Schema( 5 | { 6 | name: { type: String, unique: true, required: true }, 7 | alias: { type: String, unique: true, required: true }, 8 | type: { type: String, required: true }, 9 | createdBy: { 10 | type: mongoose.Schema.Types.ObjectId, 11 | required: true, 12 | default: "000000000000", 13 | }, 14 | updatedBy: { 15 | type: mongoose.Schema.Types.ObjectId, 16 | required: true, 17 | default: "000000000000", 18 | }, 19 | }, 20 | { timestamps: true } 21 | ); 22 | 23 | // indices 24 | // text index for name 25 | schema.index({ name: "text" }); 26 | 27 | schema.index({ type: 1 }); 28 | 29 | // index for createdAt and updatedAt 30 | schema.index({ createdAt: 1 }); 31 | schema.index({ updatedAt: 1 }); 32 | 33 | const ModelName = "Resource"; 34 | 35 | module.exports = { Model: mongoose.model(ModelName, schema), name: ModelName }; 36 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Card.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Card(theme) { 4 | return { 5 | MuiCard: { 6 | styleOverrides: { 7 | root: { 8 | position: 'relative', 9 | boxShadow: theme.customShadows.card, 10 | borderRadius: Number(theme.shape.borderRadius) * 2, 11 | zIndex: 0, // Fix Safari overflow: hidden with border radius 12 | }, 13 | }, 14 | }, 15 | MuiCardHeader: { 16 | defaultProps: { 17 | titleTypographyProps: { variant: 'h6' }, 18 | subheaderTypographyProps: { variant: 'body2', marginTop: theme.spacing(0.5) }, 19 | }, 20 | styleOverrides: { 21 | root: { 22 | padding: theme.spacing(3, 3, 0), 23 | }, 24 | }, 25 | }, 26 | MuiCardContent: { 27 | styleOverrides: { 28 | root: { 29 | padding: theme.spacing(3), 30 | }, 31 | }, 32 | }, 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /server-nest/src/modules/resource/entity/resource.entity.ts: -------------------------------------------------------------------------------- 1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; 2 | import { Document, Schema as MongooseSchema } from 'mongoose'; 3 | 4 | @Schema() 5 | export class Resource extends Document { 6 | @Prop({ type: String, unique: true, required: false }) name: string; 7 | @Prop({ type: String, unique: true, required: false }) alias: string; 8 | @Prop({ type: String, required: false }) type: string; 9 | @Prop({ 10 | type: MongooseSchema.Types.ObjectId, 11 | required: false, 12 | default: '000000000000', 13 | }) 14 | createdBy: MongooseSchema.Types.ObjectId; 15 | @Prop({ 16 | type: MongooseSchema.Types.ObjectId, 17 | required: false, 18 | default: '000000000000', 19 | }) 20 | updatedBy: MongooseSchema.Types.ObjectId; 21 | 22 | @Prop({ type: Date, default: Date.now }) 23 | updatedAt: Date; 24 | @Prop({ type: Date, default: Date.now }) 25 | createdAt: Date; 26 | } 27 | 28 | export const ResourceSchema = SchemaFactory.createForClass(Resource); 29 | -------------------------------------------------------------------------------- /client/src/_mock/phoneNumber.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const phoneNumber = [ 4 | '365-374-4961', 5 | '904-966-2836', 6 | '399-757-9909', 7 | '692-767-2903', 8 | '990-588-5716', 9 | '955-439-2578', 10 | '226-924-4058', 11 | '552-917-1454', 12 | '285-840-9338', 13 | '306-269-2446', 14 | '883-373-6253', 15 | '476-509-8866', 16 | '201-465-1954', 17 | '538-295-9408', 18 | '531-492-6028', 19 | '981-699-7588', 20 | '500-268-4826', 21 | '205-952-3828', 22 | '222-255-5190', 23 | '408-439-8033', 24 | '272-940-8266', 25 | '812-685-8057', 26 | '353-801-5212', 27 | '606-285-8928', 28 | '202-767-8621', 29 | '222-830-0731', 30 | '964-940-3166', 31 | '262-702-2396', 32 | '886-261-9789', 33 | '352-390-5069', 34 | '343-907-8334', 35 | '575-347-2399', 36 | '749-228-5604', 37 | '774-452-2071', 38 | '607-841-0447', 39 | '395-619-2157', 40 | '233-834-0373', 41 | '586-880-2602', 42 | '746-772-0722', 43 | '638-615-3365,' 44 | ]; 45 | -------------------------------------------------------------------------------- /client/src/components/animate/MotionContainer.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { m } from 'framer-motion'; 3 | // @mui 4 | import { Box } from '@mui/material'; 5 | // 6 | import { varContainer } from './variants'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | MotionContainer.propTypes = { 11 | action: PropTypes.bool, 12 | animate: PropTypes.bool, 13 | children: PropTypes.node.isRequired 14 | }; 15 | 16 | export default function MotionContainer({ animate, action = false, children, ...other }) { 17 | if (action) { 18 | return ( 19 | 26 | {children} 27 | 28 | ); 29 | } 30 | 31 | return ( 32 | 33 | {children} 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { JwtPayload } from './jwt-payload.interface'; 2 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 3 | import { PassportStrategy } from '@nestjs/passport'; 4 | import { ExtractJwt, Strategy } from 'passport-jwt'; 5 | import { AuthService } from './auth.service'; 6 | import { jwtConstants } from './constants'; 7 | 8 | @Injectable() 9 | export class JwtStrategy extends PassportStrategy(Strategy) { 10 | constructor(private readonly authService: AuthService) { 11 | super({ 12 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 13 | ignoreExpiration: false, 14 | secretOrKey: jwtConstants.secret, 15 | }); 16 | } 17 | 18 | async validate(payload: JwtPayload) { 19 | const user = await this.authService.validateUser( 20 | payload.username, 21 | payload.password, 22 | ); 23 | if (!user) { 24 | throw new UnauthorizedException(); 25 | } 26 | console.log('JwtStrategy validate user----', user); 27 | return user; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Switch.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Switch(theme) { 4 | const isLight = theme.palette.mode === 'light'; 5 | 6 | return { 7 | MuiSwitch: { 8 | styleOverrides: { 9 | thumb: { 10 | boxShadow: theme.customShadows.z1, 11 | }, 12 | track: { 13 | opacity: 1, 14 | backgroundColor: theme.palette.grey[500], 15 | }, 16 | switchBase: { 17 | left: 0, 18 | right: 'auto', 19 | '&:not(:.Mui-checked)': { 20 | color: theme.palette.grey[isLight ? 100 : 300], 21 | }, 22 | '&.Mui-checked.Mui-disabled, &.Mui-disabled': { 23 | color: theme.palette.grey[isLight ? 400 : 600], 24 | }, 25 | '&.Mui-disabled+.MuiSwitch-track': { 26 | opacity: 1, 27 | backgroundColor: `${theme.palette.action.disabledBackground} !important`, 28 | }, 29 | }, 30 | }, 31 | }, 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /client/src/components/skeleton/SkeletonKanbanColumn.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Stack, Skeleton, Box, Paper } from '@mui/material'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function SkeletonKanbanColumn() { 7 | return ( 8 | 15 | {[...Array(3)].map((_, index) => ( 16 | 17 | 18 | 19 | {index === 0 && ( 20 | 21 | )} 22 | {index !== 2 && ( 23 | 24 | )} 25 | 26 | 27 | ))} 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /client/src/pages/About.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { styled } from '@mui/material/styles'; 3 | import { Divider } from '@mui/material'; 4 | // components 5 | import Page from '../components/Page'; 6 | import { AboutHero, AboutWhat, AboutTeam, AboutVision, AboutTestimonials } from '../sections/about'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | const RootStyle = styled('div')(({ theme }) => ({ 11 | paddingTop: theme.spacing(8), 12 | [theme.breakpoints.up('md')]: { 13 | paddingTop: theme.spacing(11), 14 | }, 15 | })); 16 | 17 | // ---------------------------------------------------------------------- 18 | 19 | export default function About() { 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /client/src/redux/rootReducer.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { persistReducer } from 'redux-persist'; 3 | import storage from 'redux-persist/lib/storage'; 4 | // slices 5 | import mailReducer from './slices/mail'; 6 | import chatReducer from './slices/chat'; 7 | import productReducer from './slices/product'; 8 | import calendarReducer from './slices/calendar'; 9 | import kanbanReducer from './slices/kanban'; 10 | 11 | // ---------------------------------------------------------------------- 12 | 13 | const rootPersistConfig = { 14 | key: 'root', 15 | storage, 16 | keyPrefix: 'redux-', 17 | whitelist: [], 18 | }; 19 | 20 | const productPersistConfig = { 21 | key: 'product', 22 | storage, 23 | keyPrefix: 'redux-', 24 | whitelist: ['sortBy', 'checkout'], 25 | }; 26 | 27 | const rootReducer = combineReducers({ 28 | mail: mailReducer, 29 | chat: chatReducer, 30 | calendar: calendarReducer, 31 | kanban: kanbanReducer, 32 | product: persistReducer(productPersistConfig, productReducer), 33 | }); 34 | 35 | export { rootPersistConfig, rootReducer }; 36 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Fab.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Fab(theme) { 4 | return { 5 | MuiFab: { 6 | defaultProps: { 7 | color: 'primary', 8 | }, 9 | 10 | styleOverrides: { 11 | root: { 12 | boxShadow: theme.customShadows.z8, 13 | '&:hover': { 14 | boxShadow: 'none', 15 | backgroundColor: theme.palette.grey[400], 16 | }, 17 | }, 18 | primary: { 19 | boxShadow: theme.customShadows.primary, 20 | '&:hover': { 21 | backgroundColor: theme.palette.primary.dark, 22 | }, 23 | }, 24 | secondary: { 25 | boxShadow: theme.customShadows.secondary, 26 | '&:hover': { 27 | backgroundColor: theme.palette.secondary.dark, 28 | }, 29 | }, 30 | extended: { 31 | '& svg': { 32 | marginRight: theme.spacing(1), 33 | }, 34 | }, 35 | }, 36 | }, 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Accordion.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function Accordion(theme) { 4 | return { 5 | MuiAccordion: { 6 | styleOverrides: { 7 | root: { 8 | '&.Mui-expanded': { 9 | boxShadow: theme.customShadows.z8, 10 | borderRadius: theme.shape.borderRadius, 11 | }, 12 | '&.Mui-disabled': { 13 | backgroundColor: 'transparent', 14 | }, 15 | }, 16 | }, 17 | }, 18 | MuiAccordionSummary: { 19 | styleOverrides: { 20 | root: { 21 | paddingLeft: theme.spacing(2), 22 | paddingRight: theme.spacing(1), 23 | '&.Mui-disabled': { 24 | opacity: 1, 25 | color: theme.palette.action.disabled, 26 | '& .MuiTypography-root': { 27 | color: 'inherit', 28 | }, 29 | }, 30 | }, 31 | expandIconWrapper: { 32 | color: 'inherit', 33 | }, 34 | }, 35 | }, 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /client/src/sections/map/dynamic-styling/index.js: -------------------------------------------------------------------------------- 1 | import MapGL from 'react-map-gl'; 2 | import { useState } from 'react'; 3 | // components 4 | import { 5 | MapControlScale, 6 | MapControlGeolocate, 7 | MapControlNavigation, 8 | MapControlFullscreen, 9 | } from '../../../components/map'; 10 | // 11 | import ControlPanel from './ControlPanel'; 12 | 13 | // ---------------------------------------------------------------------- 14 | 15 | export default function MapDynamicStyling({ ...other }) { 16 | const [mapStyle, setMapStyle] = useState(''); 17 | const [viewport, setViewport] = useState({ 18 | latitude: 37.805, 19 | longitude: -122.447, 20 | zoom: 15.5, 21 | bearing: 0, 22 | pitch: 0, 23 | }); 24 | 25 | return ( 26 | <> 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /server/src/modules/permission/service.js: -------------------------------------------------------------------------------- 1 | const { ObjectId } = require("mongoose").Types; 2 | const { name } = require("./model"); 3 | 4 | const getQuery = (payload) => { 5 | const createdBySubQuery = { createdBy: ObjectId(payload.userId) }; 6 | const subQueries = []; 7 | subQueries.push(createdBySubQuery); 8 | let query = {}; 9 | let roleQuery = {}; 10 | if (payload.roleId) { 11 | roleQuery = { roleId: ObjectId(payload.roleId) }; 12 | subQueries.push(roleQuery); 13 | } 14 | 15 | let nameQuery = []; 16 | if (payload.name) { 17 | nameQuery = { 18 | $or: [ 19 | { roleAlias: { $regex: payload.name, $options: "i" } }, 20 | { resourceAlias: { $regex: payload.name, $options: "i" } }, 21 | { roleName: { $regex: payload.name, $options: "i" } }, 22 | { resourceName: { $regex: payload.name, $options: "i" } }, 23 | ], 24 | }; 25 | subQueries.push(nameQuery); 26 | } 27 | 28 | query = { 29 | $and: [...subQueries], 30 | }; 31 | return query; 32 | }; 33 | 34 | module.exports = { 35 | getQuery, 36 | modelName: name, 37 | }; 38 | -------------------------------------------------------------------------------- /client/public/icons/ic_booking.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/components/hook-form/RHFEditor.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // form 3 | import { useFormContext, Controller } from 'react-hook-form'; 4 | // @mui 5 | import { FormHelperText } from '@mui/material'; 6 | // 7 | import Editor from '../editor'; 8 | 9 | // ---------------------------------------------------------------------- 10 | 11 | RHFEditor.propTypes = { 12 | name: PropTypes.string, 13 | }; 14 | 15 | export default function RHFEditor({ name, ...other }) { 16 | const { control } = useFormContext(); 17 | 18 | return ( 19 | ( 23 | 30 | {error?.message} 31 | 32 | } 33 | {...other} 34 | /> 35 | )} 36 | /> 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /client/src/components/map/MapControlScale.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { ScaleControl } from 'react-map-gl'; 3 | // @mui 4 | import { styled } from '@mui/material/styles'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | const RootStyle = styled('div')(({ theme }) => ({ 9 | zIndex: 99, 10 | position: 'absolute', 11 | left: theme.spacing(1.5), 12 | bottom: theme.spacing(3.5), 13 | boxShadow: theme.customShadows.z8, 14 | '& .mapboxgl-ctrl': { 15 | border: 'none', 16 | borderRadius: 4, 17 | lineHeight: '14px', 18 | color: theme.palette.common.white, 19 | backgroundImage: `linear-gradient(to right, #8a2387, #e94057, #f27121)`, 20 | }, 21 | })); 22 | 23 | // ---------------------------------------------------------------------- 24 | 25 | MapControlScale.propTypes = { 26 | sx: PropTypes.object, 27 | }; 28 | 29 | export default function MapControlScale({ sx, ...other }) { 30 | return ( 31 | 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /client/src/utils/createAvatar.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | const PRIMARY_NAME = ['A', 'N', 'H', 'L', 'Q', '9', '8']; 4 | const INFO_NAME = ['F', 'G', 'T', 'I', 'J', '1', '2', '3']; 5 | const SUCCESS_NAME = ['K', 'D', 'Y', 'B', 'O', '4', '5']; 6 | const WARNING_NAME = ['P', 'E', 'R', 'S', 'C', 'U', '6', '7']; 7 | const ERROR_NAME = ['V', 'W', 'X', 'M', 'Z']; 8 | 9 | function getFirstCharacter(name) { 10 | return name && name.charAt(0).toUpperCase(); 11 | } 12 | 13 | function getAvatarColor(name) { 14 | if (PRIMARY_NAME.includes(getFirstCharacter(name))) return 'primary'; 15 | if (INFO_NAME.includes(getFirstCharacter(name))) return 'info'; 16 | if (SUCCESS_NAME.includes(getFirstCharacter(name))) return 'success'; 17 | if (WARNING_NAME.includes(getFirstCharacter(name))) return 'warning'; 18 | if (ERROR_NAME.includes(getFirstCharacter(name))) return 'warning'; 19 | return 'default'; 20 | } 21 | 22 | export default function createAvatar(name) { 23 | return { 24 | name: getFirstCharacter(name), 25 | color: getAvatarColor(name), 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /client/src/_mock/role.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const role = [ 4 | 'UX Designer', 5 | 'Full Stack Designer', 6 | 'Backend Developer', 7 | 'UX Designer', 8 | 'UX Designer', 9 | 'Project Manager', 10 | 'Leader', 11 | 'Backend Developer', 12 | 'Project Manager', 13 | 'UI Designer', 14 | 'UI/UX Designer', 15 | 'UI/UX Designer', 16 | 'UI Designer', 17 | 'Backend Developer', 18 | 'Backend Developer', 19 | 'Front End Developer', 20 | 'Backend Developer', 21 | 'Full Stack Designer', 22 | 'Full Stack Developer', 23 | 'Backend Developer', 24 | 'UX Designer', 25 | 'UI Designer', 26 | 'Project Manager', 27 | 'UI/UX Designer', 28 | 'UI Designer', 29 | 'Project Manager', 30 | 'Full Stack Developer', 31 | 'Hr Manager', 32 | 'Hr Manager', 33 | 'UI/UX Designer', 34 | 'Project Manager', 35 | 'Full Stack Designer', 36 | 'UI Designer', 37 | 'Leader', 38 | 'Front End Developer', 39 | 'UI/UX Designer', 40 | 'Project Manager', 41 | 'UI/UX Designer', 42 | 'UI Designer', 43 | 'Full Stack Designer' 44 | ]; 45 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/e-commerce/shop/ShopProductList.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Box } from '@mui/material'; 3 | import PropTypes from 'prop-types'; 4 | // components 5 | import { SkeletonProductItem } from '../../../../components/skeleton'; 6 | // 7 | import ShopProductCard from './ShopProductCard'; 8 | 9 | // ---------------------------------------------------------------------- 10 | 11 | ShopProductList.propTypes = { 12 | products: PropTypes.array.isRequired, 13 | loading: PropTypes.bool, 14 | }; 15 | 16 | export default function ShopProductList({ products, loading }) { 17 | return ( 18 | 30 | {(loading ? [...Array(12)] : products).map((product, index) => 31 | product ? : 32 | )} 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /client/src/components/InputStyle.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { styled } from '@mui/material/styles'; 3 | import { TextField } from '@mui/material'; 4 | 5 | // ---------------------------------------------------------------------- 6 | 7 | const InputStyle = styled(TextField, { 8 | shouldForwardProp: (prop) => prop !== 'stretchStart', 9 | })(({ stretchStart, theme }) => ({ 10 | '& .MuiOutlinedInput-root': { 11 | transition: theme.transitions.create(['box-shadow', 'width'], { 12 | easing: theme.transitions.easing.easeInOut, 13 | duration: theme.transitions.duration.shorter, 14 | }), 15 | '&.Mui-focused': { 16 | boxShadow: theme.customShadows.z12, 17 | }, 18 | ...(stretchStart && { 19 | width: stretchStart, 20 | '&.Mui-focused': { 21 | boxShadow: theme.customShadows.z12, 22 | [theme.breakpoints.up('sm')]: { 23 | width: stretchStart + 60, 24 | }, 25 | }, 26 | }), 27 | }, 28 | '& fieldset': { 29 | borderWidth: `1px !important`, 30 | borderColor: `${theme.palette.grey[500_32]} !important`, 31 | }, 32 | })); 33 | 34 | export default InputStyle; 35 | -------------------------------------------------------------------------------- /client/src/pages/dashboard/BlogNewPost.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Container } from '@mui/material'; 3 | // routes 4 | import { PATH_DASHBOARD } from '../../routes/paths'; 5 | // hooks 6 | import useSettings from '../../hooks/useSettings'; 7 | // components 8 | import Page from '../../components/Page'; 9 | import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'; 10 | // sections 11 | import { BlogNewPostForm } from '../../sections/@dashboard/blog'; 12 | 13 | // ---------------------------------------------------------------------- 14 | 15 | export default function BlogNewPost() { 16 | const { themeStretch } = useSettings(); 17 | 18 | return ( 19 | 20 | 21 | 29 | 30 | 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /client/src/sections/@dashboard/chat/index.js: -------------------------------------------------------------------------------- 1 | export { default as ChatRoom } from './ChatRoom'; 2 | export { default as ChatWindow } from './ChatWindow'; 3 | export { default as ChatAccount } from './ChatAccount'; 4 | export { default as ChatSidebar } from './ChatSidebar'; 5 | export { default as ChatMessageItem } from './ChatMessageItem'; 6 | export { default as ChatMessageList } from './ChatMessageList'; 7 | export { default as ChatHeaderDetail } from './ChatHeaderDetail'; 8 | export { default as ChatMessageInput } from './ChatMessageInput'; 9 | export { default as ChatContactSearch } from './ChatContactSearch'; 10 | export { default as ChatHeaderCompose } from './ChatHeaderCompose'; 11 | export { default as ChatSearchResults } from './ChatSearchResults'; 12 | export { default as ChatRoomAttachment } from './ChatRoomAttachment'; 13 | export { default as ChatConversationItem } from './ChatConversationItem'; 14 | export { default as ChatConversationList } from './ChatConversationList'; 15 | export { default as ChatRoomOneParticipant } from './ChatRoomOneParticipant'; 16 | export { default as ChatRoomGroupParticipant } from './ChatRoomGroupParticipant'; 17 | -------------------------------------------------------------------------------- /client/src/hooks/useLocalStorage.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function useLocalStorage(key, defaultValue) { 6 | const [value, setValue] = useState(() => { 7 | const storedValue = localStorage.getItem(key); 8 | return storedValue === null ? defaultValue : JSON.parse(storedValue); 9 | }); 10 | 11 | useEffect(() => { 12 | const listener = (e) => { 13 | if (e.storageArea === localStorage && e.key === key) { 14 | setValue(JSON.parse(e.newValue)); 15 | } 16 | }; 17 | window.addEventListener('storage', listener); 18 | 19 | return () => { 20 | window.removeEventListener('storage', listener); 21 | }; 22 | }, [key, defaultValue]); 23 | 24 | const setValueInLocalStorage = (newValue) => { 25 | setValue((currentValue) => { 26 | const result = typeof newValue === 'function' ? newValue(currentValue) : newValue; 27 | localStorage.setItem(key, JSON.stringify(result)); 28 | return result; 29 | }); 30 | }; 31 | 32 | return [value, setValueInLocalStorage]; 33 | } 34 | -------------------------------------------------------------------------------- /server/src/modules/permission/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | // Schema 4 | 5 | const permissionSchema = new mongoose.Schema( 6 | { 7 | roleId: { type: mongoose.Schema.Types.ObjectId, ref: "Role" }, 8 | roleName: { type: String, required: true }, 9 | roleAlias: { type: String, required: true }, 10 | resourceId: { type: mongoose.Schema.Types.ObjectId, ref: "Resource" }, 11 | resourceName: { type: String, required: true }, 12 | resourceAlias: { type: String, required: true }, 13 | isAllowed: { type: Boolean, required: true }, 14 | isDisabled: { type: Boolean, required: true }, 15 | createdBy: { 16 | type: mongoose.Schema.Types.ObjectId, 17 | required: true, 18 | default: "000000000000", 19 | }, 20 | updatedBy: { 21 | type: mongoose.Schema.Types.ObjectId, 22 | required: true, 23 | default: "000000000000", 24 | }, 25 | }, 26 | { timestamps: true } 27 | ); 28 | 29 | // reference model 30 | const ModelName = "Permission"; 31 | const Permission = mongoose.model(ModelName, permissionSchema); 32 | 33 | module.exports = { Model: Permission, name: ModelName }; 34 | -------------------------------------------------------------------------------- /client/src/pages/ComponentsOverview.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { styled } from '@mui/material/styles'; 3 | import { Container } from '@mui/material'; 4 | // components 5 | import Page from '../components/Page'; 6 | // sections 7 | // eslint-disable-next-line import/extensions,import/no-unresolved 8 | import { ComponentHero, ComponentOther, ComponentFoundation, ComponentMUI } from '../sections/overview'; 9 | 10 | // ---------------------------------------------------------------------- 11 | 12 | const RootStyle = styled('div')(({ theme }) => ({ 13 | paddingTop: theme.spacing(8), 14 | paddingBottom: theme.spacing(15), 15 | [theme.breakpoints.up('md')]: { 16 | paddingTop: theme.spacing(11), 17 | }, 18 | })); 19 | 20 | // ---------------------------------------------------------------------- 21 | 22 | export default function ComponentsOverview() { 23 | return ( 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /client/src/_mock/number.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const price = [ 4 | 16.19, 35.71, 34.3, 93.1, 55.47, 89.09, 44.39, 26.92, 45.35, 26.96, 78.22, 35.54, 90.69, 63.61, 5 | 67.55, 94.75, 75.78, 39.6, 52.84, 72.8, 83.08, 85.02, 69.22, 60.96, 84.7, 16.68, 78.83, 58.07, 6 | 65.8, 55.69, 87.55, 44.74, 27.42, 84, 76.17, 43.83, 76.39, 17.42, 42.3, 12.45 7 | ]; 8 | 9 | export const rating = [ 10 | 2.5, 2, 4.9, 2, 4, 5, 4.9, 5, 3.7, 2.5, 2, 4.9, 4.8, 4, 2, 3.7, 1.4, 2.4, 1.8, 5, 2.9, 3.9, 3.9, 11 | 1.8, 5, 2.6, 3.1, 3.9, 1.2, 3.2, 4.1, 5, 4.5, 4.1, 2.3, 2.4, 5, 3.1, 4.9, 1.7 12 | ]; 13 | 14 | export const age = [ 15 | 52, 43, 56, 25, 22, 53, 38, 50, 55, 37, 16, 27, 55, 41, 52, 32, 34, 52, 31, 53, 23, 48, 43, 41, 16 | 19, 21, 17, 29, 32, 54, 38, 34, 49, 33, 55, 50, 24, 27, 23, 23 17 | ]; 18 | 19 | export const percent = [ 20 | 8.62, 86.36, 73.99, 79, 63.41, 58.79, 12.32, 88.44, 45.06, 91.64, 88.41, 73.08, 39.14, 89.34, 21 | 43.37, 34.45, 24.04, 80.96, 72.91, 47.59, 2.46, 3.33, 99.31, 47.6, 34.09, 50.61, 66.13, 46.69, 22 | 92.43, 31.41, 90.85, 36.32, 38.84, 25.6, 87.61, 1.31, 89.32, 41.23, 85.9, 62.63 23 | ]; 24 | -------------------------------------------------------------------------------- /client/src/pages/Contact.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { styled } from '@mui/material/styles'; 3 | import { Grid, Container } from '@mui/material'; 4 | // components 5 | import Page from '../components/Page'; 6 | import { ContactHero, ContactForm, ContactMap } from '../sections/contact'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | const RootStyle = styled('div')(({ theme }) => ({ 11 | paddingTop: theme.spacing(8), 12 | [theme.breakpoints.up('md')]: { 13 | paddingTop: theme.spacing(11), 14 | }, 15 | })); 16 | 17 | // ---------------------------------------------------------------------- 18 | 19 | export default function Contact() { 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Checkbox.js: -------------------------------------------------------------------------------- 1 | // 2 | import { CheckboxIcon, CheckboxCheckedIcon, CheckboxIndeterminateIcon } from './CustomIcons'; 3 | 4 | // ---------------------------------------------------------------------- 5 | 6 | export default function Checkbox(theme) { 7 | return { 8 | MuiCheckbox: { 9 | defaultProps: { 10 | icon: , 11 | checkedIcon: , 12 | indeterminateIcon: , 13 | }, 14 | 15 | styleOverrides: { 16 | root: { 17 | padding: theme.spacing(1), 18 | '&.Mui-checked.Mui-disabled, &.Mui-disabled': { 19 | color: theme.palette.action.disabled, 20 | }, 21 | '& .MuiSvgIcon-fontSizeMedium': { 22 | width: 24, 23 | height: 24, 24 | }, 25 | '& .MuiSvgIcon-fontSizeSmall': { 26 | width: 20, 27 | height: 20, 28 | }, 29 | svg: { 30 | fontSize: 24, 31 | '&[font-size=small]': { 32 | fontSize: 20, 33 | }, 34 | }, 35 | }, 36 | }, 37 | }, 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /client/src/components/mega-menu/MenuHotProducts.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Link as RouterLink } from 'react-router-dom'; 3 | // @mui 4 | import { Link, Typography, Box } from '@mui/material'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | MenuHotProducts.propTypes = { 9 | tags: PropTypes.array.isRequired, 10 | }; 11 | 12 | export default function MenuHotProducts({ tags, ...other }) { 13 | return ( 14 | 15 | 16 | Hot Products: 17 | 18 |   19 | {tags.map((tag, index) => ( 20 | theme.transitions.create('all'), 29 | '&:hover': { color: 'primary.main' }, 30 | }} 31 | > 32 | {index === 0 ? tag.name : `, ${tag.name} `} 33 | 34 | ))} 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /client/src/layouts/dashboard/navbar/NavbarDocs.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Stack, Button, Typography } from '@mui/material'; 3 | // hooks 4 | import useAuth from '../../../hooks/useAuth'; 5 | // routes 6 | import { PATH_DOCS } from '../../../routes/paths'; 7 | // assets 8 | import { DocIllustration } from '../../../assets'; 9 | 10 | // ---------------------------------------------------------------------- 11 | 12 | export default function NavbarDocs() { 13 | const { user } = useAuth(); 14 | 15 | return ( 16 | 20 | 21 | 22 |
23 | 24 | Hi, {user?.displayName} 25 | 26 | 27 | Need help? 28 |
Please check our docs 29 |
30 |
31 | 32 | 35 |
36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /server/setup/migrate.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | require("dotenv").config(); 3 | const logger = require("../src/core/logger"); 4 | 5 | const { migrate: userMigrate } = require("./users"); 6 | const { migrate: resourceMigrate } = require("./resources"); 7 | const { migrate: roleMigrate } = require("./roles"); 8 | const { migrate: permissionMigrate } = require("./permissions"); 9 | 10 | logger.info("Migration starting"); 11 | const isMongoDbUrl = JSON.parse( 12 | process.env.IS_MONGODB_CLOUD_URL ? process.env.IS_MONGODB_CLOUD_URL : "false" 13 | ); 14 | const uri = isMongoDbUrl 15 | ? process.env.MONGODB_CLOUD_URL 16 | : `mongodb://${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`; 17 | const options = { useNewUrlParser: true, useUnifiedTopology: true }; 18 | 19 | const migrate = async () => { 20 | logger.info("Connecting to database"); 21 | await mongoose.connect(uri, options); 22 | logger.info("Connected to MongoDB"); 23 | await userMigrate(logger); 24 | await resourceMigrate(logger); 25 | await roleMigrate(logger); 26 | await permissionMigrate(logger); 27 | logger.info(`Migration finished`); 28 | process.exit(0); 29 | }; 30 | 31 | migrate(); 32 | -------------------------------------------------------------------------------- /client/src/components/Avatar.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { forwardRef } from 'react'; 3 | import { useTheme } from '@mui/material/styles'; 4 | import { Avatar as MUIAvatar } from '@mui/material'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | const Avatar = forwardRef(({ color = 'default', children, sx, ...other }, ref) => { 9 | const theme = useTheme(); 10 | 11 | if (color === 'default') { 12 | return ( 13 | 14 | {children} 15 | 16 | ); 17 | } 18 | 19 | return ( 20 | 30 | {children} 31 | 32 | ); 33 | }); 34 | 35 | Avatar.propTypes = { 36 | children: PropTypes.node, 37 | sx: PropTypes.object, 38 | color: PropTypes.oneOf(['default', 'primary', 'secondary', 'info', 'success', 'warning', 'error']), 39 | }; 40 | 41 | export default Avatar; 42 | -------------------------------------------------------------------------------- /client/src/guards/AuthGuard.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useState } from 'react'; 3 | import { Navigate, useLocation } from 'react-router-dom'; 4 | // hooks 5 | import useAuth from '../hooks/useAuth'; 6 | // pages 7 | import Login from '../pages/auth/Login'; 8 | // components 9 | import LoadingScreen from '../components/LoadingScreen'; 10 | 11 | // ---------------------------------------------------------------------- 12 | 13 | AuthGuard.propTypes = { 14 | children: PropTypes.node, 15 | }; 16 | 17 | export default function AuthGuard({ children }) { 18 | const { isAuthenticated, isInitialized } = useAuth(); 19 | const { pathname } = useLocation(); 20 | const [requestedLocation, setRequestedLocation] = useState(null); 21 | 22 | if (!isInitialized) { 23 | return ; 24 | } 25 | 26 | if (!isAuthenticated) { 27 | if (pathname !== requestedLocation) { 28 | setRequestedLocation(pathname); 29 | } 30 | return ; 31 | } 32 | 33 | if (requestedLocation && pathname !== requestedLocation) { 34 | setRequestedLocation(null); 35 | return ; 36 | } 37 | 38 | return <>{children}; 39 | } 40 | -------------------------------------------------------------------------------- /client/src/assets/index.js: -------------------------------------------------------------------------------- 1 | export { default as DocIllustration } from './illustration_doc'; 2 | export { default as SeoIllustration } from './illustration_seo'; 3 | export { default as UploadIllustration } from './illustration_upload'; 4 | export { default as SeverErrorIllustration } from './illustration_500'; 5 | export { default as PageNotFoundIllustration } from './illustration_404'; 6 | export { default as MotivationIllustration } from './illustration_motivation'; 7 | export { default as ComingSoonIllustration } from './illustration_coming_soon'; 8 | export { default as MaintenanceIllustration } from './illustration_maintenance'; 9 | export { default as OrderCompleteIllustration } from './illustration_order_complete'; 10 | export { default as BookingIllustration } from './illustration_booking'; 11 | export { default as CheckInIllustration } from './illustration_checkin'; 12 | export { default as CheckOutIllustration } from './illustration_checkout'; 13 | // 14 | export { default as SentIcon } from './icon_sent'; 15 | export { default as PlanFreeIcon } from './icon_plan_free'; 16 | export { default as PlanStarterIcon } from './icon_plan_starter'; 17 | export { default as PlanPremiumIcon } from './icon_plan_premium'; 18 | -------------------------------------------------------------------------------- /client/src/theme/overrides/Pagination.js: -------------------------------------------------------------------------------- 1 | import { alpha } from '@mui/material/styles'; 2 | 3 | // ---------------------------------------------------------------------- 4 | 5 | export default function Pagination(theme) { 6 | return { 7 | MuiPaginationItem: { 8 | styleOverrides: { 9 | root: { 10 | '&.Mui-selected': { 11 | fontWeight: theme.typography.fontWeightBold, 12 | }, 13 | }, 14 | textPrimary: { 15 | '&.Mui-selected': { 16 | color: theme.palette.primary.main, 17 | backgroundColor: alpha(theme.palette.primary.main, 0.08), 18 | '&:hover, &.Mui-focusVisible': { 19 | backgroundColor: `${alpha(theme.palette.primary.main, 0.24)} !important`, 20 | }, 21 | }, 22 | }, 23 | outlined: { 24 | border: `1px solid ${theme.palette.grey[500_32]}`, 25 | }, 26 | outlinedPrimary: { 27 | '&.Mui-selected': { 28 | backgroundColor: alpha(theme.palette.primary.main, 0.08), 29 | border: `1px solid ${alpha(theme.palette.primary.main, 0.24)}`, 30 | }, 31 | }, 32 | }, 33 | }, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /server/src/modules/role/controller.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { getQuery } = require("./service"); 3 | const { 4 | getByIdHandler, 5 | saveHandler, 6 | updateHandler, 7 | searchHandler: baseSearchHandler, 8 | countHandler: baseCountHandler, 9 | deleteHandler, 10 | } = require("../../core/controller"); 11 | const { validate } = require("./request"); 12 | const { handleValidation } = require("../../common/middlewares"); 13 | 14 | const router = express.Router(); 15 | 16 | const searchHandler = async (req, res, next) => { 17 | req.searchQuery = getQuery({ ...req.body, userId: req.user.id }); 18 | return baseSearchHandler(req, res, next); 19 | }; 20 | 21 | const countHandler = async (req, res, next) => { 22 | req.searchQuery = getQuery({ ...req.body, userId: req.user.id }); 23 | return baseCountHandler(req, res, next); 24 | }; 25 | 26 | router.get("/detail", getByIdHandler); 27 | router.post("/create", handleValidation(validate), saveHandler); 28 | router.put("/update", handleValidation(validate), updateHandler); 29 | router.post("/search", searchHandler); 30 | router.post("/count", countHandler); 31 | router.delete("/delete", deleteHandler); 32 | 33 | module.exports = router; 34 | -------------------------------------------------------------------------------- /client/src/sections/auth/AuthFirebaseSocial.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Stack, Button, Divider, Typography } from '@mui/material'; 3 | // components 4 | import Iconify from '../../components/Iconify'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | export default function AuthFirebaseSocial() { 9 | return ( 10 | <> 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | OR 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /server/src/modules/permission/controller.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { getQuery } = require("./service"); 3 | const { 4 | getByIdHandler, 5 | saveHandler, 6 | updateHandler, 7 | searchHandler: baseSearchHandler, 8 | countHandler: baseCountHandler, 9 | deleteHandler, 10 | } = require("../../core/controller"); 11 | const { validate } = require("./request"); 12 | const { handleValidation } = require("../../common/middlewares"); 13 | 14 | const router = express.Router(); 15 | 16 | const searchHandler = async (req, res, next) => { 17 | req.searchQuery = getQuery({ ...req.body, userId: req.user.id }); 18 | return baseSearchHandler(req, res, next); 19 | }; 20 | 21 | const countHandler = async (req, res, next) => { 22 | req.searchQuery = getQuery({ ...req.body, userId: req.user.id }); 23 | return baseCountHandler(req, res, next); 24 | }; 25 | 26 | router.get("/detail", getByIdHandler); 27 | router.post("/create", handleValidation(validate), saveHandler); 28 | router.put("/update", handleValidation(validate), updateHandler); 29 | router.post("/search", searchHandler); 30 | router.post("/count", countHandler); 31 | router.delete("/delete", deleteHandler); 32 | 33 | module.exports = router; 34 | -------------------------------------------------------------------------------- /server/src/modules/salesOrder/controller.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | const express = require("express"); 3 | const { getQuery } = require("./service"); 4 | const { 5 | getByIdHandler, 6 | saveHandler, 7 | updateHandler, 8 | searchHandler: baseSearchHandler, 9 | countHandler: baseCountHandler, 10 | deleteHandler, 11 | } = require("../../core/controller"); 12 | 13 | const router = express.Router(); 14 | 15 | const searchHandler = async (req, res, next) => { 16 | console.log("salesOrder searchHandler body---------- ", req.body); 17 | req.searchQuery = getQuery(req.body); 18 | return baseSearchHandler(req, res, next); 19 | }; 20 | 21 | const countHandler = async (req, res, next) => { 22 | req.searchQuery = getQuery(req.body); 23 | return baseCountHandler(req, res, next); 24 | }; 25 | 26 | router.get("/detail", getByIdHandler); 27 | router.post( 28 | "/create", 29 | // handleValidation(validate), 30 | saveHandler 31 | ); 32 | router.put( 33 | "/update", 34 | // handleValidation(validate), 35 | updateHandler 36 | ); 37 | 38 | router.post("/search", searchHandler); 39 | router.post("/count", countHandler); 40 | router.delete("/delete", deleteHandler); 41 | 42 | module.exports = router; 43 | -------------------------------------------------------------------------------- /client/src/components/ThemeColorPresets.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useMemo } from 'react'; 3 | // @mui 4 | import { alpha, ThemeProvider, createTheme, useTheme } from '@mui/material/styles'; 5 | // hooks 6 | import useSettings from '../hooks/useSettings'; 7 | // 8 | import componentsOverride from '../theme/overrides'; 9 | 10 | // ---------------------------------------------------------------------- 11 | 12 | ThemeColorPresets.propTypes = { 13 | children: PropTypes.node, 14 | }; 15 | 16 | export default function ThemeColorPresets({ children }) { 17 | const defaultTheme = useTheme(); 18 | const { setColor } = useSettings(); 19 | 20 | const themeOptions = useMemo( 21 | () => ({ 22 | ...defaultTheme, 23 | palette: { 24 | ...defaultTheme.palette, 25 | primary: setColor, 26 | }, 27 | customShadows: { 28 | ...defaultTheme.customShadows, 29 | primary: `0 8px 16px 0 ${alpha(setColor.main, 0.24)}`, 30 | }, 31 | }), 32 | [setColor, defaultTheme] 33 | ); 34 | 35 | const theme = createTheme(themeOptions); 36 | theme.components = componentsOverride(theme); 37 | 38 | return {children}; 39 | } 40 | -------------------------------------------------------------------------------- /client/src/components/upload/BlockContent.js: -------------------------------------------------------------------------------- 1 | // @mui 2 | import { Box, Typography, Stack } from '@mui/material'; 3 | // assets 4 | import { UploadIllustration } from '../../assets'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | export default function BlockContent() { 9 | return ( 10 | 17 | 18 | 19 | 20 | 21 | Drop or Select file 22 | 23 | 24 | 25 | Drop files here or click  26 | 31 | browse 32 | 33 |  thorough your machine 34 | 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /server-nest/src/modules/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { JwtModule, JwtService } from '@nestjs/jwt'; 3 | import { PassportModule } from '@nestjs/passport'; 4 | import { AuthController } from './auth.controller'; 5 | import { AuthService } from './auth.service'; 6 | import { JwtStrategy } from './jwt.strategy'; 7 | import { LocalStrategy } from './local.strategy'; 8 | // import { UserService } from '../user/user.service'; 9 | import { UserModule } from '../user/user.module'; 10 | // import { UserServiceProvider } from 'src/users/users.provider'; 11 | import { jwtConstants } from './constants'; 12 | import { PermissionModule } from '../permission/permission.module'; 13 | 14 | @Module({ 15 | imports: [ 16 | PassportModule.register({ defaultStrategy: 'jwt' }), 17 | JwtModule.register({ 18 | // secretOrPrivateKey: 'secretKey', 19 | secret: jwtConstants.secret, 20 | signOptions: { expiresIn: '100000s' }, 21 | }), 22 | UserModule, 23 | PermissionModule, 24 | ], 25 | controllers: [AuthController], 26 | providers: [ 27 | AuthService, 28 | LocalStrategy, 29 | JwtStrategy, 30 | // ...UserServiceProvider, 31 | ], 32 | }) 33 | export class AuthModule {} 34 | -------------------------------------------------------------------------------- /server-nest/src/modules/location/location.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Controller, 3 | Get, 4 | Post, 5 | Body, 6 | Param, 7 | Put, 8 | Delete, 9 | } from '@nestjs/common'; 10 | import { LocationService } from './location.service'; 11 | import { CreateLocationDto } from './dto/createLocation.dto'; 12 | 13 | @Controller('api/locations') 14 | export class LocationController { 15 | constructor(private readonly locationService: LocationService) {} 16 | 17 | @Get() 18 | async findAll() { 19 | return this.locationService.getAllLocations(); 20 | } 21 | 22 | @Get(':id') 23 | async findOne(@Param('id') id: number) { 24 | return this.locationService.getLocationById(id); 25 | } 26 | 27 | @Post() 28 | async create(@Body() createLocationDto: CreateLocationDto) { 29 | return this.locationService.createLocation(createLocationDto); 30 | } 31 | 32 | @Put(':id') 33 | async update( 34 | @Param('id') id: number, 35 | @Body() updateLocationDto: CreateLocationDto, 36 | ) { 37 | return this.locationService.updateLocation(id, updateLocationDto); 38 | } 39 | 40 | @Delete(':id') 41 | async delete(@Param('id') id: number) { 42 | return this.locationService.deleteLocation(id); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /client/src/components/map/MapControlMarker.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Marker } from 'react-map-gl'; 3 | // @mui 4 | import { styled } from '@mui/material/styles'; 5 | 6 | // ---------------------------------------------------------------------- 7 | 8 | const ICON = `M20.2,15.7L20.2,15.7c1.1-1.6,1.8-3.6,1.8-5.7c0-5.6-4.5-10-10-10S2,4.5,2,10c0,2,0.6,3.9,1.6,5.4c0,0.1,0.1,0.2,0.2,0.3 9 | c0,0,0.1,0.1,0.1,0.2c0.2,0.3,0.4,0.6,0.7,0.9c2.6,3.1,7.4,7.6,7.4,7.6s4.8-4.5,7.4-7.5c0.2-0.3,0.5-0.6,0.7-0.9 10 | C20.1,15.8,20.2,15.8,20.2,15.7z`; 11 | const SIZE = 20; 12 | 13 | const IconStyle = styled('svg')(({ theme }) => ({ 14 | height: SIZE, 15 | stroke: 'none', 16 | cursor: 'pointer', 17 | fill: theme.palette.error.main, 18 | transform: `translate(${-SIZE / 2}px,${-SIZE}px)`, 19 | })); 20 | 21 | // ---------------------------------------------------------------------- 22 | 23 | MapControlMarker.propTypes = { 24 | onClick: PropTypes.func, 25 | }; 26 | 27 | export default function MapControlMarker({ onClick, ...other }) { 28 | return ( 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /client/src/components/nav-section/horizontal/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { memo } from 'react'; 3 | // @mui 4 | import { Stack } from '@mui/material'; 5 | // 6 | import { NavListRoot } from './NavList'; 7 | 8 | // ---------------------------------------------------------------------- 9 | 10 | const hideScrollbar = { 11 | msOverflowStyle: 'none', 12 | scrollbarWidth: 'none', 13 | overflowY: 'scroll', 14 | '&::-webkit-scrollbar': { 15 | display: 'none', 16 | }, 17 | }; 18 | 19 | NavSectionHorizontal.propTypes = { 20 | navConfig: PropTypes.array, 21 | }; 22 | 23 | function NavSectionHorizontal({ navConfig }) { 24 | return ( 25 | 26 | 27 | {navConfig.map((group) => ( 28 | 29 | {group.items.map((list) => ( 30 | 31 | ))} 32 | 33 | ))} 34 | 35 | 36 | ); 37 | } 38 | 39 | export default memo(NavSectionHorizontal); 40 | -------------------------------------------------------------------------------- /client/src/theme/overrides/CssBaseline.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export default function CssBaseline() { 4 | return { 5 | MuiCssBaseline: { 6 | styleOverrides: { 7 | '*': { 8 | margin: 0, 9 | padding: 0, 10 | boxSizing: 'border-box', 11 | }, 12 | html: { 13 | width: '100%', 14 | height: '100%', 15 | WebkitOverflowScrolling: 'touch', 16 | }, 17 | body: { 18 | width: '100%', 19 | height: '100%', 20 | }, 21 | '#root': { 22 | width: '100%', 23 | height: '100%', 24 | }, 25 | input: { 26 | '&[type=number]': { 27 | MozAppearance: 'textfield', 28 | '&::-webkit-outer-spin-button': { 29 | margin: 0, 30 | WebkitAppearance: 'none', 31 | }, 32 | '&::-webkit-inner-spin-button': { 33 | margin: 0, 34 | WebkitAppearance: 'none', 35 | }, 36 | }, 37 | }, 38 | img: { 39 | display: 'block', 40 | maxWidth: '100%', 41 | }, 42 | }, 43 | }, 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /server-nest/src/modules/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { ClientSession, Schema as MongooseSchema } from 'mongoose'; 3 | import { UserRepository } from './repository/user.repository'; 4 | import { CreateUserDto } from './dto/createUser.dto'; 5 | import { JwtPayload } from '../auth/jwt-payload.interface'; 6 | import { User } from './entity/user.entity'; 7 | import * as bcrypt from 'bcrypt'; 8 | import * as mongoose from 'mongoose'; 9 | 10 | @Injectable() 11 | export class UserService { 12 | constructor(private readonly userRepository: UserRepository) {} 13 | 14 | async createUser(createUserDto: CreateUserDto, session: ClientSession) { 15 | const createdUser = await this.userRepository.createUser( 16 | createUserDto, 17 | session, 18 | ); 19 | return createdUser; 20 | } 21 | async findByUsername(payload: JwtPayload): Promise { 22 | return await this.userRepository.getUserByUsername(payload.username); 23 | } 24 | async compareHash(password: string, hash: string): Promise { 25 | return bcrypt.compare(password, hash); 26 | } 27 | async getUserById(id: MongooseSchema.Types.ObjectId) { 28 | return await this.userRepository.getUserById(id); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/src/_mock/company.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | 3 | export const company = [ 4 | 'Lueilwitz and Sons', 5 | 'Gleichner, Mueller and Tromp', 6 | 'Nikolaus - Leuschke', 7 | 'Hegmann, Kreiger and Bayer', 8 | 'Grimes Inc', 9 | 'Durgan - Murazik', 10 | 'Altenwerth, Medhurst and Roberts', 11 | 'Raynor Group', 12 | 'Mraz, Donnelly and Collins', 13 | 'Padberg - Bailey', 14 | 'Heidenreich, Stokes and Parker', 15 | 'Pagac and Sons', 16 | 'Rempel, Hand and Herzog', 17 | 'Dare - Treutel', 18 | 'Kihn, Marquardt and Crist', 19 | 'Nolan - Kunde', 20 | 'Wuckert Inc', 21 | 'Dibbert Inc', 22 | 'Goyette and Sons', 23 | 'Feest Group', 24 | 'Bosco and Sons', 25 | 'Bartell - Kovacek', 26 | 'Schimmel - Raynor', 27 | 'Tremblay LLC', 28 | 'Hills - Mitchell', 29 | 'Rogahn LLC', 30 | 'Kuhn, Osinski and Morar', 31 | 'Schmitt Inc', 32 | 'Breitenberg - Rosenbaum', 33 | "O'Keefe, Schneider and Mraz", 34 | 'Rohan, Langworth and Kling', 35 | 'Morar and Sons', 36 | 'Mraz LLC', 37 | 'Rowe, Parisian and Kub', 38 | 'Marquardt - Hane', 39 | 'Medhurst Group', 40 | 'Nikolaus - Lang', 41 | 'Effertz, Mohr and Olson', 42 | 'Anderson - Kris', 43 | 'Runolfsson Group' 44 | ]; 45 | --------------------------------------------------------------------------------