├── mobile ├── .gitattributes ├── assets │ ├── icon.png │ ├── splash.png │ ├── car-door.png │ ├── co2-max-icon.png │ ├── co2-min-icon.png │ ├── rating-icon.png │ ├── distance-icon.png │ ├── splash-tablet.png │ └── co2-middle-icon.png ├── lang │ └── i18n.ts ├── services │ ├── axiosInstance.ts │ ├── SettingService.ts │ └── SupplierService.ts ├── components │ ├── AutocompleteDropdown-v4.3.1 │ │ ├── types │ │ │ └── global.d.ts │ │ ├── helpers.ts │ │ ├── useKeyboardHeight.ts │ │ ├── theme.tsx │ │ └── NothingFound.tsx │ ├── AutocompleteDropdown-v4 │ │ ├── types │ │ │ └── global.d.ts │ │ ├── helpers.ts │ │ ├── useKeyboardHeight.ts │ │ ├── theme.tsx │ │ └── NothingFound.tsx │ ├── Indicator.tsx │ ├── Error.tsx │ ├── AutocompleteDropdown-v2 │ │ ├── NothingFound.tsx │ │ └── HOC │ │ │ └── withFadeAnimation.tsx │ ├── Backdrop.tsx │ └── Link.tsx ├── tsconfig.json ├── utils │ ├── toastHelper.ts │ └── axiosHelper.ts ├── .env.example ├── babel.config.js ├── eas.json └── context │ └── GlobalContext.tsx ├── .husky └── pre-commit ├── admin ├── .stylelintrc.json ├── src │ ├── vite-env.d.ts │ ├── assets │ │ ├── css │ │ │ ├── search.css │ │ │ ├── index.css │ │ │ ├── error.css │ │ │ ├── progress.css │ │ │ ├── contact.css │ │ │ ├── booking-filter.css │ │ │ ├── vehicle-scheduler-filter.css │ │ │ ├── tos.css │ │ │ ├── driver-license.css │ │ │ ├── deposit-filter.css │ │ │ ├── parking-spot-edit-list.css │ │ │ ├── info-box.css │ │ │ ├── pager.css │ │ │ ├── contact-form.css │ │ │ ├── gearbox-filter.css │ │ │ ├── mileage-filter.css │ │ │ ├── car-type-filter.css │ │ │ ├── car-specs-filter.css │ │ │ ├── car-seats-filter.css │ │ │ ├── car-range-filter.css │ │ │ ├── fuel-policy-filter.css │ │ │ ├── availability-filter.css │ │ │ ├── update-supplier.css │ │ │ ├── car-multimedia-filter.css │ │ │ ├── about.css │ │ │ ├── change-password.css │ │ │ ├── bank-details.css │ │ │ ├── contract-list.css │ │ │ ├── create-supplier.css │ │ │ ├── date-based-price-edit-list.css │ │ │ ├── update-country.css │ │ │ ├── create-location.css │ │ │ ├── update-location.css │ │ │ ├── create-country.css │ │ │ ├── create-user.css │ │ │ ├── forgot-password.css │ │ │ └── car-rating-filter.css │ │ └── img │ │ │ ├── car-door.png │ │ │ ├── co2-max-icon.png │ │ │ ├── co2-min-icon.png │ │ │ ├── rating-icon.png │ │ │ ├── co2-middle-icon.png │ │ │ └── distance-icon.png │ ├── config │ │ └── const.ts │ ├── models │ │ ├── SearchForm.ts │ │ ├── ForgotPasswordForm.ts │ │ ├── BankDetailsForm.ts │ │ ├── ContactForm.ts │ │ ├── BookingFilterForm.ts │ │ ├── CountryForm.ts │ │ ├── common.ts │ │ ├── SignInForm.ts │ │ ├── ActivateForm.ts │ │ ├── ResetPasswordForm.ts │ │ ├── SettingsForm.ts │ │ ├── SignUpForm.ts │ │ ├── ChangePasswordForm.ts │ │ └── LocationForm.ts │ ├── components │ │ ├── scheduler │ │ │ ├── helpers │ │ │ │ └── constants.ts │ │ │ ├── hooks │ │ │ │ └── useStore.ts │ │ │ ├── store │ │ │ │ └── context.ts │ │ │ ├── positionManger │ │ │ │ ├── usePosition.ts │ │ │ │ └── context.ts │ │ │ ├── index.tsx │ │ │ └── components │ │ │ │ ├── hoc │ │ │ │ └── DateProvider.tsx │ │ │ │ └── events │ │ │ │ └── EmptyAgenda.tsx │ │ ├── ScrollToTop.tsx │ │ ├── PositionInput.tsx │ │ ├── NProgressIndicator.tsx │ │ ├── Progress.tsx │ │ ├── InfoBox.tsx │ │ ├── Unauthorized.tsx │ │ ├── Error.tsx │ │ └── SupplierBadge.tsx │ ├── services │ │ ├── axiosInstance.ts │ │ └── SettingService.ts │ ├── lang │ │ ├── contract-list.ts │ │ ├── users.ts │ │ ├── bookings.ts │ │ ├── no-match.ts │ │ ├── unauthorized.ts │ │ ├── create-booking.ts │ │ ├── update-user.ts │ │ ├── parking-spot-edit-list.ts │ │ ├── create-user.ts │ │ ├── booking-filter.ts │ │ ├── booking.ts │ │ ├── update-country.ts │ │ ├── suppliers.ts │ │ ├── update-location.ts │ │ ├── booking-car-list.ts │ │ ├── car-range-filter.ts │ │ ├── car-seats-filter.ts │ │ ├── activate.ts │ │ ├── multimedia-list.ts │ │ ├── contact-form.ts │ │ ├── car-rating-filter.ts │ │ ├── car-specs.ts │ │ ├── date-based-price-edit-list.ts │ │ ├── create-country.ts │ │ ├── settings.ts │ │ ├── car-multimedia-filter.ts │ │ └── supplier-list.ts │ ├── pages │ │ ├── ToS.tsx │ │ ├── Notifications.tsx │ │ ├── Error.tsx │ │ ├── Contact.tsx │ │ └── NoMatch.tsx │ └── utils │ │ ├── customHooks.ts │ │ └── langHelper.ts ├── public │ ├── favicon.ico │ └── robots.txt ├── types │ └── eslint-plugin-react-compiler.d.ts ├── tsconfig.node.json ├── index.html ├── Dockerfile ├── .gitignore ├── nginx.conf └── Dockerfile.dev ├── frontend ├── src │ ├── vite-env.d.ts │ ├── assets │ │ ├── img │ │ │ ├── maxi.png │ │ │ ├── midi.png │ │ │ ├── mini.png │ │ │ ├── paypal.png │ │ │ ├── stripe.png │ │ │ ├── car-door.png │ │ │ ├── apple-icon.png │ │ │ ├── co2-max-icon.png │ │ │ ├── co2-min-icon.png │ │ │ ├── google-icon.png │ │ │ ├── rating-icon.png │ │ │ ├── view-on-map.png │ │ │ ├── distance-icon.png │ │ │ ├── facebook-icon.png │ │ │ └── co2-middle-icon.png │ │ └── css │ │ │ ├── no-match.css │ │ │ ├── badge.css │ │ │ ├── error.css │ │ │ ├── progress.css │ │ │ ├── suppliers.css │ │ │ ├── locations.css │ │ │ ├── contact.css │ │ │ ├── index.css │ │ │ ├── booking-filter.css │ │ │ ├── map-dialog.css │ │ │ ├── faq.css │ │ │ ├── newsletter-form.css │ │ │ ├── tos.css │ │ │ ├── privacy.css │ │ │ ├── cookie-policy.css │ │ │ ├── driver-license.css │ │ │ ├── checkout-session.css │ │ │ ├── deposit-filter.css │ │ │ ├── view-on-map-button.css │ │ │ ├── extras.css │ │ │ ├── faq-list.css │ │ │ ├── supplier-carrousel.css │ │ │ ├── map.css │ │ │ ├── pager.css │ │ │ ├── contact-form.css │ │ │ ├── gearbox-filter.css │ │ │ ├── mileage-filter.css │ │ │ ├── car-type-filter.css │ │ │ ├── car-specs-filter.css │ │ │ ├── car-seats-filter.css │ │ │ ├── fuel-policy-filter.css │ │ │ ├── car-range-filter.css │ │ │ ├── social-login.css │ │ │ ├── car-multimedia-filter.css │ │ │ ├── about.css │ │ │ ├── toast.css │ │ │ ├── car-rating-filter.css │ │ │ ├── multiple-select.css │ │ │ └── car-filter.css │ ├── config │ │ └── const.ts │ ├── services │ │ ├── axiosInstance.ts │ │ ├── IpInfoService.ts │ │ ├── SettingService.ts │ │ └── CountryService.ts │ ├── models │ │ ├── NewsletterForm.ts │ │ ├── ForgotPasswordForm.ts │ │ ├── ContactForm.ts │ │ ├── BookingFilterForm.ts │ │ ├── SignInForm.ts │ │ ├── ActivateForm.ts │ │ ├── ResetPasswordForm.ts │ │ ├── ChangePasswordForm.ts │ │ └── SettingsForm.ts │ ├── components │ │ ├── ScrollToTop.tsx │ │ ├── NProgressIndicator.tsx │ │ ├── Badge.tsx │ │ ├── Progress.tsx │ │ ├── ViewOnMapButton.tsx │ │ ├── Unauthorized.tsx │ │ ├── TabPanel.tsx │ │ ├── Error.tsx │ │ └── SimpleBackdrop.tsx │ ├── lang │ │ ├── booking.ts │ │ ├── bookings.ts │ │ ├── view-on-map-button.ts │ │ ├── no-match.ts │ │ ├── unauthorized.ts │ │ ├── search.ts │ │ ├── booking-filter.ts │ │ ├── booking-car-list.ts │ │ ├── map.ts │ │ ├── car-range-filter.ts │ │ ├── sign-up.ts │ │ ├── car-seats-filter.ts │ │ ├── activate.ts │ │ ├── location-carrousel.ts │ │ ├── contact-form.ts │ │ ├── car-rating-filter.ts │ │ ├── car-specs.ts │ │ ├── car-multimedia-filter.ts │ │ ├── settings.ts │ │ └── newsletter-form.ts │ ├── utils │ │ ├── useAnalytics.ts │ │ ├── customHooks.ts │ │ └── langHelper.ts │ └── pages │ │ ├── Faq.tsx │ │ ├── ToS.tsx │ │ ├── Suppliers.tsx │ │ ├── Privacy.tsx │ │ ├── CookiePolicy.tsx │ │ ├── Notifications.tsx │ │ ├── Error.tsx │ │ ├── Contact.tsx │ │ ├── Info.tsx │ │ └── NoMatch.tsx ├── .stylelintrc.json ├── public │ ├── cover.mp4 │ ├── cover.png │ ├── cover.webp │ ├── favicon.ico │ └── robots.txt ├── types │ └── eslint-plugin-react-compiler.d.ts ├── tsconfig.node.json ├── Dockerfile ├── .gitignore ├── index.html ├── nginx.conf └── Dockerfile.dev ├── __scripts ├── swap-usage.sh ├── utils.sh ├── bc-logs.sh ├── free-mem.sh ├── swap.sh ├── bc-deploy-backend.sh ├── bc-deploy.sh ├── bc-deploy-frontend.sh └── bc-deploy-admin.sh ├── .vscode ├── extensions.json └── settings.json ├── backend ├── __tests__ │ ├── img │ │ ├── bmw-x1.jpg │ │ ├── bmw-x5.jpg │ │ ├── avatar1.jpg │ │ ├── avatar2.png │ │ ├── location0.jpg │ │ ├── location1.jpg │ │ └── location2.jpg │ ├── licenses │ │ ├── license1.pdf │ │ └── license2.pdf │ └── contracts │ │ ├── contract1.pdf │ │ └── contract2.pdf ├── src │ ├── config │ │ ├── ipinfoRoutes.config.ts │ │ ├── settingRoutes.config.ts │ │ ├── bankDetailsRoutes.config.ts │ │ ├── paypalRoutes.config.ts │ │ ├── stripeRoutes.config.ts │ │ ├── notificationRoutes.config.ts │ │ ├── countryRoutes.config.ts │ │ ├── bookingRoutes.config.ts │ │ ├── supplierRoutes.config.ts │ │ ├── locationRoutes.config.ts │ │ └── carRoutes.config.ts │ ├── payment │ │ └── stripe.ts │ ├── lang │ │ └── i18n.ts │ ├── routes │ │ ├── ipinfoRoutes.ts │ │ ├── paypalRoutes.ts │ │ ├── settingRoutes.ts │ │ ├── bankDetailsRoutes.ts │ │ ├── stripeRoutes.ts │ │ └── notificationRoutes.ts │ ├── controllers │ │ └── ipinfoController.ts │ ├── utils │ │ └── databaseTTLHelper.ts │ ├── models │ │ ├── PushToken.ts │ │ ├── DateBasedPrice.ts │ │ ├── Country.ts │ │ ├── BankDetails.ts │ │ ├── Setting.ts │ │ ├── ParkingSpot.ts │ │ └── NotificationCounter.ts │ └── middlewares │ │ └── allowedMethods.ts ├── nodemon.json ├── Dockerfile ├── .gitignore ├── jest.config.json ├── babel.config.js └── scripts │ └── db.ts ├── .github ├── FUNDING.yml └── latest-release.json ├── codecov.yml ├── .gitignore ├── packages ├── currency-converter │ ├── check.ts │ └── package.json ├── .gitignore ├── reactjs-social-login │ ├── .gitignore │ ├── package.json │ └── tsconfig.json ├── disable-react-devtools │ ├── package.json │ └── index.ts ├── bookcars-types │ └── package.json └── bookcars-helper │ └── package.json ├── .dockerignore └── __services └── bookcars.service /mobile/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | npm run pre-commit 4 | -------------------------------------------------------------------------------- /admin/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { "extends": ["stylelint-config-standard"] } -------------------------------------------------------------------------------- /admin/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { "extends": ["stylelint-config-standard"] } -------------------------------------------------------------------------------- /__scripts/swap-usage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | grep '^Swap' /proc/meminfo 4 | -------------------------------------------------------------------------------- /admin/src/assets/css/search.css: -------------------------------------------------------------------------------- 1 | .sc-search { 2 | width: 235px; 3 | } 4 | -------------------------------------------------------------------------------- /__scripts/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | grep CRON-FREE-MEM /var/log/syslog 4 | -------------------------------------------------------------------------------- /__scripts/bc-logs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | tail -f /opt/bookcars/backend/logs/all.log 4 | -------------------------------------------------------------------------------- /mobile/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/icon.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /admin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/cover.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/public/cover.mp4 -------------------------------------------------------------------------------- /frontend/public/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/public/cover.png -------------------------------------------------------------------------------- /mobile/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/splash.png -------------------------------------------------------------------------------- /admin/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: / 4 | -------------------------------------------------------------------------------- /frontend/public/cover.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/public/cover.webp -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /mobile/assets/car-door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/car-door.png -------------------------------------------------------------------------------- /mobile/assets/co2-max-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/co2-max-icon.png -------------------------------------------------------------------------------- /mobile/assets/co2-min-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/co2-min-icon.png -------------------------------------------------------------------------------- /mobile/assets/rating-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/rating-icon.png -------------------------------------------------------------------------------- /backend/__tests__/img/bmw-x1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/bmw-x1.jpg -------------------------------------------------------------------------------- /backend/__tests__/img/bmw-x5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/bmw-x5.jpg -------------------------------------------------------------------------------- /frontend/src/assets/img/maxi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/maxi.png -------------------------------------------------------------------------------- /frontend/src/assets/img/midi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/midi.png -------------------------------------------------------------------------------- /frontend/src/assets/img/mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/mini.png -------------------------------------------------------------------------------- /mobile/assets/distance-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/distance-icon.png -------------------------------------------------------------------------------- /mobile/assets/splash-tablet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/splash-tablet.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: aelassas 2 | buy_me_a_coffee: aelassas 3 | custom: ["https://www.paypal.me/aelassaspp"] 4 | -------------------------------------------------------------------------------- /admin/src/assets/css/index.css: -------------------------------------------------------------------------------- 1 | .app { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | } 6 | -------------------------------------------------------------------------------- /admin/src/assets/img/car-door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/src/assets/img/car-door.png -------------------------------------------------------------------------------- /backend/__tests__/img/avatar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/avatar1.jpg -------------------------------------------------------------------------------- /backend/__tests__/img/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/avatar2.png -------------------------------------------------------------------------------- /backend/__tests__/img/location0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/location0.jpg -------------------------------------------------------------------------------- /backend/__tests__/img/location1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/location1.jpg -------------------------------------------------------------------------------- /backend/__tests__/img/location2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/img/location2.jpg -------------------------------------------------------------------------------- /frontend/src/assets/img/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/paypal.png -------------------------------------------------------------------------------- /frontend/src/assets/img/stripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/stripe.png -------------------------------------------------------------------------------- /mobile/assets/co2-middle-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/mobile/assets/co2-middle-icon.png -------------------------------------------------------------------------------- /.github/latest-release.json: -------------------------------------------------------------------------------- 1 | {"latestApkUrl": "https://github.com/aelassas/bookcars/releases/download/v8.3/bookcars-8.3.apk"} 2 | -------------------------------------------------------------------------------- /admin/src/assets/img/co2-max-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/src/assets/img/co2-max-icon.png -------------------------------------------------------------------------------- /admin/src/assets/img/co2-min-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/src/assets/img/co2-min-icon.png -------------------------------------------------------------------------------- /admin/src/assets/img/rating-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/src/assets/img/rating-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/car-door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/car-door.png -------------------------------------------------------------------------------- /admin/src/assets/img/co2-middle-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/src/assets/img/co2-middle-icon.png -------------------------------------------------------------------------------- /admin/src/assets/img/distance-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/admin/src/assets/img/distance-icon.png -------------------------------------------------------------------------------- /backend/__tests__/licenses/license1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/licenses/license1.pdf -------------------------------------------------------------------------------- /backend/__tests__/licenses/license2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/licenses/license2.pdf -------------------------------------------------------------------------------- /frontend/src/assets/css/no-match.css: -------------------------------------------------------------------------------- 1 | .no-match { 2 | margin: 15px; 3 | } 4 | 5 | .no-match h2 { 6 | color: #232323; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/assets/img/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/apple-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/co2-max-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/co2-max-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/co2-min-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/co2-min-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/google-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/google-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/rating-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/rating-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/view-on-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/view-on-map.png -------------------------------------------------------------------------------- /backend/__tests__/contracts/contract1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/contracts/contract1.pdf -------------------------------------------------------------------------------- /backend/__tests__/contracts/contract2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/backend/__tests__/contracts/contract2.pdf -------------------------------------------------------------------------------- /frontend/src/assets/img/distance-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/distance-icon.png -------------------------------------------------------------------------------- /frontend/src/assets/img/facebook-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/facebook-icon.png -------------------------------------------------------------------------------- /backend/src/config/ipinfoRoutes.config.ts: -------------------------------------------------------------------------------- 1 | const routes = { 2 | getCountryCode: '/api/country-code', 3 | } 4 | 5 | export default routes 6 | -------------------------------------------------------------------------------- /frontend/src/assets/img/co2-middle-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aelassas/bookcars/HEAD/frontend/src/assets/img/co2-middle-icon.png -------------------------------------------------------------------------------- /backend/src/config/settingRoutes.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | getSettings: '/api/settings', 3 | updateSettings: '/api/update-settings', 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/assets/css/badge.css: -------------------------------------------------------------------------------- 1 | div.badge { 2 | font-size: 11px; 3 | border-radius: 10px; 4 | width: fit-content; 5 | padding: 3px 12px; 6 | } 7 | -------------------------------------------------------------------------------- /__scripts/free-mem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | free -h 4 | sudo sysctl -w vm.drop_caches=3 5 | sudo sync 6 | echo 3 | sudo tee /proc/sys/vm/drop_caches 7 | free -h 8 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: off # disables overall project coverage check 4 | patch: off # disables patch coverage check 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /**/*.key 2 | /**/*.crt 3 | /**/*.pem 4 | /**/*.pem-chain 5 | /**/*.ca.pem 6 | /**/.DS_Store 7 | /**/dist 8 | /node_modules 9 | .eslintcache 10 | -------------------------------------------------------------------------------- /admin/src/assets/css/error.css: -------------------------------------------------------------------------------- 1 | /* Error */ 2 | 3 | .error { 4 | color: #ec5555; 5 | text-align: center; 6 | } 7 | 8 | .message { 9 | padding: 5px; 10 | } 11 | -------------------------------------------------------------------------------- /admin/src/assets/css/progress.css: -------------------------------------------------------------------------------- 1 | div.progress { 2 | width: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | padding: 10px 0; 7 | } 8 | -------------------------------------------------------------------------------- /backend/src/config/bankDetailsRoutes.config.ts: -------------------------------------------------------------------------------- 1 | const routes = { 2 | upsert: '/api/upsert-bank-details', 3 | get: '/api/bank-details', 4 | } 5 | 6 | export default routes 7 | -------------------------------------------------------------------------------- /frontend/src/assets/css/error.css: -------------------------------------------------------------------------------- 1 | /* Error */ 2 | 3 | .error { 4 | color: #ec5555; 5 | text-align: center; 6 | } 7 | 8 | .message { 9 | padding: 5px; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/assets/css/progress.css: -------------------------------------------------------------------------------- 1 | div.progress { 2 | width: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | padding: 10px 0; 7 | } 8 | -------------------------------------------------------------------------------- /admin/src/config/const.ts: -------------------------------------------------------------------------------- 1 | const Const = { 2 | PAGINATION_MODE: { 3 | CLASSIC: 'CLASSIC', 4 | INFINITE_SCROLL: 'INFINITE_SCROLL', 5 | }, 6 | } 7 | 8 | export default Const 9 | -------------------------------------------------------------------------------- /frontend/src/config/const.ts: -------------------------------------------------------------------------------- 1 | const Const = { 2 | PAGINATION_MODE: { 3 | CLASSIC: 'CLASSIC', 4 | INFINITE_SCROLL: 'INFINITE_SCROLL', 5 | }, 6 | } 7 | 8 | export default Const 9 | -------------------------------------------------------------------------------- /admin/src/models/SearchForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | export const schema = z.object({ 4 | keyword: z.string().optional() 5 | }) 6 | 7 | export type FormFields = z.infer 8 | -------------------------------------------------------------------------------- /backend/src/payment/stripe.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe' 2 | import * as env from '../config/env.config' 3 | 4 | const stripeAPI = new Stripe(env.STRIPE_SECRET_KEY) 5 | 6 | export default stripeAPI 7 | -------------------------------------------------------------------------------- /admin/src/components/scheduler/helpers/constants.ts: -------------------------------------------------------------------------------- 1 | export const BORDER_HEIGHT = 1 2 | export const MULTI_DAY_EVENT_HEIGHT = 28 3 | export const MONTH_NUMBER_HEIGHT = 27 4 | export const MONTH_BAR_HEIGHT = 23 5 | -------------------------------------------------------------------------------- /admin/types/eslint-plugin-react-compiler.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-react-compiler' { 2 | import type { ESLint } from 'eslint' 3 | 4 | let plugin: ESLint.Plugin 5 | export default plugin 6 | } 7 | -------------------------------------------------------------------------------- /admin/src/services/axiosInstance.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import env from '@/config/env.config' 3 | 4 | const axiosInstance = axios.create({ baseURL: env.API_HOST }) 5 | 6 | export default axiosInstance 7 | -------------------------------------------------------------------------------- /frontend/types/eslint-plugin-react-compiler.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-react-compiler' { 2 | import type { ESLint } from 'eslint' 3 | 4 | let plugin: ESLint.Plugin 5 | export default plugin 6 | } 7 | -------------------------------------------------------------------------------- /backend/src/config/paypalRoutes.config.ts: -------------------------------------------------------------------------------- 1 | const routes = { 2 | createPayPalOrder: '/api/create-paypal-order', 3 | checkPayPalOrder: '/api/check-paypal-order/:bookingId/:orderId', 4 | } 5 | 6 | export default routes 7 | -------------------------------------------------------------------------------- /frontend/src/services/axiosInstance.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import env from '@/config/env.config' 3 | 4 | const axiosInstance = axios.create({ baseURL: env.API_HOST }) 5 | 6 | export default axiosInstance 7 | -------------------------------------------------------------------------------- /frontend/src/assets/css/suppliers.css: -------------------------------------------------------------------------------- 1 | div.suppliers { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | min-height: 100vh; 8 | } 9 | -------------------------------------------------------------------------------- /admin/src/components/scheduler/hooks/useStore.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { StoreContext } from '../store/context' 3 | 4 | const useStore = () => useContext(StoreContext) 5 | 6 | export default useStore 7 | -------------------------------------------------------------------------------- /admin/src/components/scheduler/store/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react' 2 | import { initialStore } from './default' 3 | import { Store } from './types' 4 | 5 | export const StoreContext = createContext(initialStore) 6 | -------------------------------------------------------------------------------- /backend/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src"], 3 | "ext": "ts", 4 | "ignore": [], 5 | "exec": "tsx --experimental-specifier-resolution=node --import ./src/monitoring/instrument.ts ./src", 6 | "legacyWatch": true 7 | } 8 | -------------------------------------------------------------------------------- /admin/src/components/scheduler/positionManger/usePosition.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { PositionContext } from './context' 3 | 4 | const usePosition = () => useContext(PositionContext) 5 | 6 | export default usePosition 7 | -------------------------------------------------------------------------------- /backend/src/lang/i18n.ts: -------------------------------------------------------------------------------- 1 | import { I18n } from 'i18n-js' 2 | import { en } from './en' 3 | import { fr } from './fr' 4 | import { es } from './es' 5 | 6 | const i18n = new I18n({ en, fr, es }) 7 | i18n.enableFallback = true 8 | export default i18n 9 | -------------------------------------------------------------------------------- /mobile/lang/i18n.ts: -------------------------------------------------------------------------------- 1 | import { I18n } from 'i18n-js' 2 | import { en } from './en' 3 | import { fr } from './fr' 4 | import { es } from './es' 5 | 6 | const i18n = new I18n({ en, fr, es }) 7 | i18n.enableFallback = true 8 | 9 | export default i18n 10 | -------------------------------------------------------------------------------- /frontend/src/assets/css/locations.css: -------------------------------------------------------------------------------- 1 | div.locations { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | } 8 | 9 | div.locations .map { 10 | height: 800px; 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/config/stripeRoutes.config.ts: -------------------------------------------------------------------------------- 1 | const routes = { 2 | createCheckoutSession: '/api/create-checkout-session', 3 | checkCheckoutSession: '/api/check-checkout-session/:sessionId', 4 | createPaymentIntent: '/api/create-payment-intent', 5 | } 6 | 7 | export default routes 8 | -------------------------------------------------------------------------------- /admin/src/assets/css/contact.css: -------------------------------------------------------------------------------- 1 | div.contact { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | min-height: 100vh; 8 | } 9 | 10 | div.contact .form { 11 | margin: 100px 0; 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/assets/css/contact.css: -------------------------------------------------------------------------------- 1 | div.contact { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | min-height: 100vh; 8 | } 9 | 10 | div.contact .form { 11 | margin: 100px 0; 12 | } 13 | -------------------------------------------------------------------------------- /frontend/src/assets/css/index.css: -------------------------------------------------------------------------------- 1 | .app { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | } 6 | 7 | /* .grecaptcha-badge { 8 | visibility: hidden !important; 9 | } */ 10 | 11 | .github-fork-ribbon::before { 12 | background-color: #272727; 13 | } 14 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM node:lts-alpine 4 | WORKDIR /bookcars/backend 5 | COPY ./backend ./ 6 | COPY ./backend/.env.docker .env 7 | COPY ./packages /bookcars/packages 8 | RUN npm install 9 | 10 | CMD [ "npm", "run", "start:setup"] 11 | EXPOSE 4002 12 | -------------------------------------------------------------------------------- /admin/src/models/ForgotPasswordForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | import { strings as commonStrings } from '@/lang/common' 3 | 4 | export const schema = z.object({ 5 | email: z.string().email({ message: commonStrings.EMAIL_NOT_VALID }) 6 | }) 7 | 8 | export type FormFields = z.infer 9 | -------------------------------------------------------------------------------- /frontend/src/models/NewsletterForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | import { strings as commonStrings } from '@/lang/common' 3 | 4 | export const schema = z.object({ 5 | email: z.string().email({ message: commonStrings.EMAIL_NOT_VALID }) 6 | }) 7 | 8 | export type FormFields = z.infer 9 | -------------------------------------------------------------------------------- /packages/currency-converter/check.ts: -------------------------------------------------------------------------------- 1 | import CurrencyConverter from './index.js' 2 | 3 | const amount = 100 4 | const currencyConverter = new CurrencyConverter({ from: 'USD', to: 'EUR', amount }) 5 | 6 | const res = await currencyConverter.convert() 7 | 8 | console.log(`${amount} USD = ${res} EUR`) 9 | -------------------------------------------------------------------------------- /admin/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/models/ForgotPasswordForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | import { strings as commonStrings } from '@/lang/common' 3 | 4 | export const schema = z.object({ 5 | email: z.string().email({ message: commonStrings.EMAIL_NOT_VALID }) 6 | }) 7 | 8 | export type FormFields = z.infer 9 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /mobile/services/axiosInstance.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import * as axiosHelper from '@/utils/axiosHelper' 3 | import * as env from '@/config/env.config' 4 | 5 | const axiosInstance = axios.create({ baseURL: env.API_HOST }) 6 | 7 | axiosHelper.init(axiosInstance) 8 | 9 | export default axiosInstance 10 | -------------------------------------------------------------------------------- /admin/src/assets/css/booking-filter.css: -------------------------------------------------------------------------------- 1 | div.booking-filter { 2 | background: #fafafa; 3 | margin: 10px 10px 0 0; 4 | border: 1px solid #dadada; 5 | font-size: 13px; 6 | } 7 | 8 | div.booking-filter .bf-search { 9 | margin-top: 7px; 10 | } 11 | 12 | div.booking-filter .btn-search { 13 | margin: 20px 0; 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/assets/css/booking-filter.css: -------------------------------------------------------------------------------- 1 | div.booking-filter { 2 | background: #fff; 3 | margin: 10px 10px 0 0; 4 | border: 1px solid #dadada; 5 | font-size: 13px; 6 | } 7 | 8 | div.booking-filter .bf-search { 9 | margin-top: 7px; 10 | } 11 | 12 | div.booking-filter .btn-search { 13 | margin: 20px 0; 14 | } 15 | -------------------------------------------------------------------------------- /admin/src/models/BankDetailsForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | export const schema = z.object({ 4 | accountHolder: z.string(), 5 | bankName: z.string(), 6 | iban: z.string(), 7 | swiftBic: z.string(), 8 | showBankDetailsPage: z.boolean(), 9 | }) 10 | 11 | export type FormFields = z.infer 12 | -------------------------------------------------------------------------------- /frontend/src/assets/css/map-dialog.css: -------------------------------------------------------------------------------- 1 | .map-dialog-content { 2 | margin: 0; 3 | width: 100%; 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | } 8 | 9 | .close-icon { 10 | color: #fff; 11 | font-size: 20px !important; 12 | } 13 | 14 | .close-btn:hover > * { 15 | color: #d1d1d1; 16 | } 17 | -------------------------------------------------------------------------------- /mobile/components/AutocompleteDropdown-v4.3.1/types/global.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace setInterval { 3 | function setInterval(callback: () => void, ms?: number | undefined): NodeJS.Timeout 4 | } 5 | namespace setTimeout { 6 | function setTimeout(callback: () => void, ms?: number | undefined): NodeJS.Timeout 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /mobile/components/AutocompleteDropdown-v4/types/global.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace setInterval { 3 | function setInterval(callback: () => void, ms?: number | undefined): NodeJS.Timeout 4 | } 5 | namespace setTimeout { 6 | function setTimeout(callback: () => void, ms?: number | undefined): NodeJS.Timeout 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /admin/src/components/ScrollToTop.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useLocation } from 'react-router-dom' 3 | 4 | const ScrollToTop = () => { 5 | const { pathname } = useLocation() 6 | 7 | useEffect(() => { 8 | window.scrollTo(0, 0) 9 | }, [pathname]) 10 | 11 | return null 12 | } 13 | 14 | export default ScrollToTop 15 | -------------------------------------------------------------------------------- /frontend/src/assets/css/faq.css: -------------------------------------------------------------------------------- 1 | div.faq { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | padding: 50px 10%; 8 | min-height: 100vh; 9 | } 10 | 11 | @media only screen and (width <=960px) { 12 | div.faq { 13 | padding: 50px 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mobile/components/Indicator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ActivityIndicator } from 'react-native' 3 | 4 | interface IndicatorProps { 5 | style?: object 6 | } 7 | 8 | const Indicator = ({ style }: IndicatorProps) => ( 9 | 10 | ) 11 | 12 | export default Indicator 13 | -------------------------------------------------------------------------------- /admin/src/models/ContactForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | import { strings as commonStrings } from '@/lang/common' 3 | 4 | export const schema = z.object({ 5 | email: z.string().email({ message: commonStrings.EMAIL_NOT_VALID }), 6 | subject: z.string(), 7 | message: z.string(), 8 | }) 9 | 10 | export type FormFields = z.infer 11 | -------------------------------------------------------------------------------- /backend/src/routes/ipinfoRoutes.ts: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | import routeNames from '../config/ipinfoRoutes.config' 3 | import * as ipinfoController from '../controllers/ipinfoController' 4 | 5 | const routes = express.Router() 6 | 7 | routes.route(routeNames.getCountryCode).get(ipinfoController.getCountryCode) 8 | 9 | export default routes 10 | -------------------------------------------------------------------------------- /frontend/src/components/ScrollToTop.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useLocation } from 'react-router-dom' 3 | 4 | const ScrollToTop = () => { 5 | const { pathname } = useLocation() 6 | 7 | useEffect(() => { 8 | window.scrollTo(0, 0) 9 | }, [pathname]) 10 | 11 | return null 12 | } 13 | 14 | export default ScrollToTop 15 | -------------------------------------------------------------------------------- /frontend/src/models/ContactForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | import { strings as commonStrings } from '@/lang/common' 3 | 4 | export const schema = z.object({ 5 | email: z.string().email({ message: commonStrings.EMAIL_NOT_VALID }), 6 | subject: z.string(), 7 | message: z.string(), 8 | }) 9 | 10 | export type FormFields = z.infer 11 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /**/.git 2 | /**/node_modules 3 | /**/dist 4 | /**/logs 5 | /**/tsconfig.tsbuildinfo 6 | /**/vite.config.d.ts 7 | /**/vite.config.js 8 | /**/.env 9 | /**/.env.example 10 | /**/.env.development 11 | /**/.env.production 12 | /**/.dockerignore 13 | /**/Dockerfile 14 | mobile/ 15 | .github/ 16 | .vscode/ 17 | __config/ 18 | __scripts/ 19 | __services/ 20 | -------------------------------------------------------------------------------- /admin/src/assets/css/vehicle-scheduler-filter.css: -------------------------------------------------------------------------------- 1 | div.vehicle-scheduler-filter { 2 | background: #fafafa; 3 | margin: 10px 10px 0 0; 4 | border: 1px solid #dadada; 5 | font-size: 13px; 6 | } 7 | 8 | div.vehicle-scheduler-filter .bf-search { 9 | margin-top: 7px; 10 | } 11 | 12 | div.vehicle-scheduler-filter .btn-search { 13 | margin: 20px 0; 14 | } 15 | -------------------------------------------------------------------------------- /admin/src/models/BookingFilterForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | export const schema = z.object({ 4 | from: z.date().optional(), 5 | to: z.date().optional(), 6 | pickupLocation: z.string().optional(), 7 | dropOffLocation: z.string().optional(), 8 | keyword: z.string().optional(), 9 | }) 10 | 11 | export type FormFields = z.infer 12 | -------------------------------------------------------------------------------- /frontend/src/models/BookingFilterForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | export const schema = z.object({ 4 | from: z.date().optional(), 5 | to: z.date().optional(), 6 | pickupLocation: z.string().optional(), 7 | dropOffLocation: z.string().optional(), 8 | keyword: z.string().optional(), 9 | }) 10 | 11 | export type FormFields = z.infer 12 | -------------------------------------------------------------------------------- /admin/src/components/PositionInput.tsx: -------------------------------------------------------------------------------- 1 | import React, { ComponentPropsWithoutRef } from 'react' 2 | import { Input } from '@mui/material' 3 | 4 | const PositionInput = (props: ComponentPropsWithoutRef) => ( 5 | 10 | ) 11 | 12 | export default PositionInput 13 | -------------------------------------------------------------------------------- /frontend/src/assets/css/newsletter-form.css: -------------------------------------------------------------------------------- 1 | form.newsletter-form div.form { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | } 6 | 7 | form.newsletter-form div.form .input { 8 | margin-right: 15px; 9 | max-width: 240px; 10 | } 11 | 12 | form.newsletter-form div.form .btn { 13 | height: 40px; 14 | padding: 0 30px; 15 | min-width: 120px; 16 | } 17 | -------------------------------------------------------------------------------- /packages/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /**/node_modules/ 5 | npm-debug.log* 6 | 7 | # TypeScript 8 | /**/*.tsbuildinfo 9 | /**/*.d.ts 10 | 11 | # JavaScript 12 | /**/*.js 13 | !eslint.config.js 14 | 15 | # misc 16 | /**/.DS_Store 17 | /**/.DS_Store? 18 | 19 | # eslint 20 | /**/.eslintcache 21 | -------------------------------------------------------------------------------- /__scripts/swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SWAP_SIZE="1G" # Swap size of 1GB 4 | 5 | # Add Swap Space 6 | echo "Adding swap space..." 7 | sudo fallocate -l $SWAP_SIZE /swapfile 8 | sudo chmod 600 /swapfile 9 | sudo mkswap /swapfile 10 | sudo swapon /swapfile 11 | 12 | # Make swap permanent 13 | echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab 14 | 15 | grep '^Swap' /proc/meminfo 16 | -------------------------------------------------------------------------------- /admin/src/models/CountryForm.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | import { strings } from '@/lang/create-country' 3 | 4 | const countryNameSchema = z.object({ 5 | language: z.string(), 6 | name: z.string().min(1, strings.INVALID_COUNTRY) 7 | }) 8 | 9 | 10 | export const schema = z.object({ 11 | names: z.array(countryNameSchema) 12 | }) 13 | 14 | export type FormFields = z.infer 15 | -------------------------------------------------------------------------------- /frontend/src/lang/booking.ts: -------------------------------------------------------------------------------- 1 | import LocalizedStrings from 'localized-strings' 2 | import * as langHelper from '@/utils/langHelper' 3 | 4 | const strings = new LocalizedStrings({ 5 | fr: { 6 | TOTAL: 'Total :', 7 | }, 8 | en: { 9 | TOTAL: 'Total:', 10 | }, 11 | es: { 12 | TOTAL: 'Total:', 13 | }, 14 | }) 15 | 16 | langHelper.setLanguage(strings) 17 | export { strings } 18 | -------------------------------------------------------------------------------- /frontend/src/services/IpInfoService.ts: -------------------------------------------------------------------------------- 1 | import axiosInstance from './axiosInstance' 2 | 3 | /** 4 | * Returns Country ISO 2 code from client IP. 5 | * 6 | * @param {string} sessionId 7 | * @returns {Promise} 8 | */ 9 | export const getCountryCode = (): Promise => 10 | axiosInstance 11 | .get( 12 | '/api/country-code', 13 | ) 14 | .then((res) => res.data) 15 | -------------------------------------------------------------------------------- /frontend/src/utils/useAnalytics.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useLocation } from 'react-router-dom' 3 | 4 | import * as analytics from './ga4' 5 | 6 | export const useAnalytics = () => { 7 | const location = useLocation() 8 | 9 | useEffect(() => { 10 | const path = location.pathname + location.search 11 | analytics.sendPageview(path) 12 | }, [location]) 13 | } 14 | -------------------------------------------------------------------------------- /__services/bookcars.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BookCars Backend Server 3 | Wants=mongod.service 4 | After=mongod.service 5 | 6 | [Service] 7 | ExecStart=/usr/bin/npm start 8 | WorkingDirectory=/opt/bookcars/backend 9 | Type=simple 10 | Restart=always 11 | StandardOutput=append:/var/log/bookcars.log 12 | StandardError=append:/var/log/bookcars.log 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /admin/src/lang/contract-list.ts: -------------------------------------------------------------------------------- 1 | import LocalizedStrings from 'localized-strings' 2 | import * as langHelper from '@/utils/langHelper' 3 | 4 | const strings = new LocalizedStrings({ 5 | fr: { 6 | TITLE: 'Contrats', 7 | }, 8 | en: { 9 | TITLE: 'Contracts', 10 | }, 11 | es: { 12 | TITLE: 'Contratos', 13 | } 14 | }) 15 | 16 | langHelper.setLanguage(strings) 17 | export { strings } 18 | -------------------------------------------------------------------------------- /backend/src/config/notificationRoutes.config.ts: -------------------------------------------------------------------------------- 1 | const routes = { 2 | notificationCounter: '/api/notification-counter/:userId', 3 | markAsRead: '/api/mark-notifications-as-read/:userId', 4 | markAsUnRead: '/api/mark-notifications-as-unread/:userId', 5 | delete: '/api/delete-notifications/:userId', 6 | getNotifications: '/api/notifications/:userId/:page/:size', 7 | } 8 | 9 | export default routes 10 | -------------------------------------------------------------------------------- /admin/src/assets/css/tos.css: -------------------------------------------------------------------------------- 1 | div.tos { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | white-space: pre-wrap; 8 | padding: 50px 20%; 9 | font-size: 15px; 10 | color: #121212; 11 | min-height: 100vh; 12 | } 13 | 14 | @media only screen and (width <=960px) { 15 | div.tos { 16 | padding: 30px 20px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /admin/src/lang/users.ts: -------------------------------------------------------------------------------- 1 | import LocalizedStrings from 'localized-strings' 2 | import * as langHelper from '@/utils/langHelper' 3 | 4 | const strings = new LocalizedStrings({ 5 | fr: { 6 | NEW_USER: 'Nouvel utilisateur', 7 | }, 8 | en: { 9 | NEW_USER: 'New user', 10 | }, 11 | es: { 12 | NEW_USER: 'Nuevo usuario', 13 | }, 14 | }) 15 | 16 | langHelper.setLanguage(strings) 17 | export { strings } 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": [ 3 | "javascript", 4 | "javascriptreact", 5 | "typescript", 6 | "typescriptreact" 7 | ], 8 | "eslint.run": "onType", 9 | "eslint.workingDirectories": [ 10 | { "directory": "backend" }, 11 | { "directory": "admin" }, 12 | { "directory": "frontend" }, 13 | { "directory": "mobile" } 14 | ], 15 | "files.insertFinalNewline": true 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/assets/css/tos.css: -------------------------------------------------------------------------------- 1 | div.tos { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | white-space: pre-wrap; 8 | padding: 50px 20%; 9 | font-size: 15px; 10 | color: #121212; 11 | min-height: 100vh; 12 | } 13 | 14 | @media only screen and (width <=960px) { 15 | div.tos { 16 | padding: 30px 20px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /admin/src/lang/bookings.ts: -------------------------------------------------------------------------------- 1 | import LocalizedStrings from 'localized-strings' 2 | import * as langHelper from '@/utils/langHelper' 3 | 4 | const strings = new LocalizedStrings({ 5 | fr: { 6 | NEW_BOOKING: 'Nouvelle réservation', 7 | }, 8 | en: { 9 | NEW_BOOKING: 'New Booking', 10 | }, 11 | es: { 12 | NEW_BOOKING: 'Nueva reserva', 13 | }, 14 | }) 15 | 16 | langHelper.setLanguage(strings) 17 | export { strings } 18 | -------------------------------------------------------------------------------- /frontend/src/assets/css/privacy.css: -------------------------------------------------------------------------------- 1 | div.privacy { 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1 0 auto; 5 | align-items: center; 6 | transform: translate3d(0, 0, 0); 7 | white-space: pre-wrap; 8 | padding: 50px 20%; 9 | font-size: 15px; 10 | color: #121212; 11 | min-height: 100vh; 12 | } 13 | 14 | @media only screen and (width <=960px) { 15 | div.privacy { 16 | padding: 30px 20px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/pages/Faq.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import FaqList from '@/components/FaqList' 3 | import Footer from '@/components/Footer' 4 | import Layout from '@/components/Layout' 5 | 6 | import '@/assets/css/faq.css' 7 | 8 | const Faq = () => ( 9 | 10 |
11 | 12 |
13 | 14 |