Full Code of idurar/idurar-erp-crm for AI

master 82ff5d1bcb8a cached
429 files
851.9 KB
240.2k tokens
270 symbols
1 requests
Download .txt
Showing preview only (958K chars total). Download the full file or copy to clipboard to get everything.
Repository: idurar/idurar-erp-crm
Branch: master
Commit: 82ff5d1bcb8a
Files: 429
Total size: 851.9 KB

Directory structure:
gitextract_uk7xy8q9/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── custom.md
│   │   └── feature_request.md
│   ├── pull_request_template.md
│   └── workflows/
│       ├── CODEOWNERS
│       ├── codesee-arch-diagram.yml
│       └── github-repo-stats.yml
├── CODE-OF-CONDUCT.md
├── CONTRIBUTING.md
├── INSTALLATION-INSTRUCTIONS.md
├── LICENSE
├── README.md
├── SECURITY.md
├── backend/
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .prettierignore
│   ├── .prettierrc
│   ├── .vscode/
│   │   └── settings.json
│   ├── jsconfig.json
│   ├── package.json
│   └── src/
│       ├── app.js
│       ├── controllers/
│       │   ├── appControllers/
│       │   │   ├── clientController/
│       │   │   │   ├── index.js
│       │   │   │   └── summary.js
│       │   │   ├── index.js
│       │   │   ├── invoiceController/
│       │   │   │   ├── create.js
│       │   │   │   ├── index.js
│       │   │   │   ├── paginatedList.js
│       │   │   │   ├── read.js
│       │   │   │   ├── remove.js
│       │   │   │   ├── schemaValidate.js
│       │   │   │   ├── sendMail.js
│       │   │   │   ├── summary.js
│       │   │   │   └── update.js
│       │   │   └── paymentController/
│       │   │       ├── create.js
│       │   │       ├── index.js
│       │   │       ├── remove.js
│       │   │       ├── sendMail.js
│       │   │       ├── summary.js
│       │   │       └── update.js
│       │   ├── coreControllers/
│       │   │   ├── adminAuth/
│       │   │   │   └── index.js
│       │   │   ├── adminController/
│       │   │   │   └── index.js
│       │   │   ├── settingController/
│       │   │   │   ├── index.js
│       │   │   │   ├── listAll.js
│       │   │   │   ├── listBySettingKey.js
│       │   │   │   ├── readBySettingKey.js
│       │   │   │   ├── updateBySettingKey.js
│       │   │   │   └── updateManySetting.js
│       │   │   └── setup.js
│       │   ├── middlewaresControllers/
│       │   │   ├── createAuthMiddleware/
│       │   │   │   ├── authUser.js
│       │   │   │   ├── checkAndCorrectURL.js
│       │   │   │   ├── forgetPassword.js
│       │   │   │   ├── index.js
│       │   │   │   ├── isValidAuthToken.js
│       │   │   │   ├── login.js
│       │   │   │   ├── logout.js
│       │   │   │   ├── resetPassword.js
│       │   │   │   └── sendMail.js
│       │   │   ├── createCRUDController/
│       │   │   │   ├── create.js
│       │   │   │   ├── filter.js
│       │   │   │   ├── index.js
│       │   │   │   ├── listAll.js
│       │   │   │   ├── paginatedList.js
│       │   │   │   ├── read.js
│       │   │   │   ├── remove.js
│       │   │   │   ├── search.js
│       │   │   │   ├── summary.js
│       │   │   │   └── update.js
│       │   │   └── createUserController/
│       │   │       ├── index.js
│       │   │       ├── read.js
│       │   │       ├── updatePassword.js
│       │   │       ├── updateProfile.js
│       │   │       └── updateProfilePassword.js
│       │   └── pdfController/
│       │       └── index.js
│       ├── emailTemplate/
│       │   ├── SendEmailTemplate.js
│       │   └── emailVerfication.js
│       ├── handlers/
│       │   ├── downloadHandler/
│       │   │   └── downloadPdf.js
│       │   └── errorHandlers.js
│       ├── helpers.js
│       ├── locale/
│       │   ├── languages.js
│       │   ├── translation/
│       │   │   └── en_us.js
│       │   └── useLanguage.js
│       ├── middlewares/
│       │   ├── inventory/
│       │   │   ├── generateUniqueNumber.js
│       │   │   └── index.js
│       │   ├── serverData.js
│       │   ├── settings/
│       │   │   ├── increaseBySettingKey.js
│       │   │   ├── index.js
│       │   │   ├── listAllSettings.js
│       │   │   ├── listBySettingKey.js
│       │   │   ├── loadSettings.js
│       │   │   ├── readBySettingKey.js
│       │   │   └── updateBySettingKey.js
│       │   └── uploadMiddleware/
│       │       ├── DoSingleStorage.js
│       │       ├── LocalSingleStorage.js
│       │       ├── index.js
│       │       ├── singleStorageUpload.js
│       │       └── utils/
│       │           ├── LocalfileFilter.js
│       │           └── fileFilterMiddleware.js
│       ├── models/
│       │   ├── .gitkeep
│       │   ├── appModels/
│       │   │   ├── Client.js
│       │   │   ├── Invoice.js
│       │   │   └── Payment.js
│       │   ├── coreModels/
│       │   │   ├── Admin.js
│       │   │   ├── AdminPassword.js
│       │   │   ├── Setting.js
│       │   │   └── Upload.js
│       │   └── utils/
│       │       └── index.js
│       ├── pdf/
│       │   ├── Invoice.pug
│       │   ├── Offer.pug
│       │   ├── Payment.pug
│       │   └── Quote.pug
│       ├── routes/
│       │   ├── appRoutes/
│       │   │   └── appApi.js
│       │   └── coreRoutes/
│       │       ├── coreApi.js
│       │       ├── coreAuth.js
│       │       ├── coreDownloadRouter.js
│       │       └── corePublicRouter.js
│       ├── server.js
│       ├── settings/
│       │   ├── index.js
│       │   ├── useAppSettings.js
│       │   ├── useDate.js
│       │   └── useMoney.js
│       ├── setup/
│       │   ├── defaultSettings/
│       │   │   ├── appSettings.json
│       │   │   ├── clientSettings.json
│       │   │   ├── companySettings.json
│       │   │   ├── financeSettings.json
│       │   │   ├── invoiceSettings.json
│       │   │   ├── moneyFormatSettings.json
│       │   │   └── quoteSettings.json
│       │   ├── reset.js
│       │   ├── setup.js
│       │   └── setupConfig.json
│       └── utils/
│           ├── countryList.js
│           ├── currency.js
│           ├── currencyList.js
│           └── is-path-inside.js
├── doc/
│   ├── README.fr.md
│   └── README.sp.md
├── features/
│   ├── ar_eg_ملف_مفتوح_المصدر_مجاني_للبرمجيات_ERP_CRM.md
│   ├── bg_bg_свободен_отворен_източник_erp_crm_софтуер.md
│   ├── bn_bd_ফ্রি_ওপেন_সোর্স_ইআরপি_সিআরএম_সফটওয়্যার.md
│   ├── ca_es_software_erp_crm_de_codi_obert_gratuït.md
│   ├── cs_cz_volný_otevřený_zdroj_erp_crm_software.md
│   ├── da_dk_gratis_åben_kilde_erp_crm_software.md
│   ├── de_de_frei_offene_quelle_erp_crm_software.md
│   ├── el_gr_ελεύθερο_ανοικτο_πηγαίο_erp_crm_λογισμικό.md
│   ├── en_us_free_open_source_erp_crm_software.md
│   ├── es_es_software_erp_crm_de_código_abierto_y_gratis.md
│   ├── et_ee_tasuta_avatud_lähtekoodiga_erp_crm_tarkvara.md
│   ├── fa_ir_رایگان_منبع_باز_نرم‌افزار_مدیریت_مالی_و_ارتباطات.md
│   ├── fi_fi_ilmainen_avoin_lähdekoodi_erp_crm_ohjelmisto.md
│   ├── fr_fr_gratuit_logiciel_erp_crm_open_source.md
│   ├── hi_in_मुफ्त_खुला_स्रोत_ईआरपी_सीआरएम_सॉफ़्टवेयर.md
│   ├── hr_hr_besplatni_otvoreni_izvor_erp_crm_softver.md
│   ├── hu_hu_ingyenes_nyílt_forráskódú_erp_crm_szoftver.md
│   ├── id_id_perangkat_lunak_erp_crm_sumber_terbuka_gratis.md
│   ├── it_it_software_erp_crm_open_source_gratuito.md
│   ├── ja_jp_フリーオープンソースERP CRMソフトウェア.md
│   ├── ko_kr_자유_오픈_소스_ERP_CRM_소프트웨어.md
│   ├── lt_lt_nemokamas_atviras_kodo_erp_crm_programinė_įranga.md
│   ├── lv_lv_bezmaksas_atvērtā_koda_erp_crm_programmatūra.md
│   ├── mk_mk_фрее_опен_сорсе_ерп_црм_софтвер.md
│   ├── ms_my_fail_terbuka_sumber_erp_crm_perisian.md
│   ├── nb_no_gratis_åpen_kilde_erp_crm_programvare.md
│   ├── nl_nl_vrije_open_source_erp_crm_software.md
│   ├── pl_pl_bezpłatne_otwarte_źródło_erp_crm_oprogramowanie.md
│   ├── pt_br_software_de_erp_e_crm_de_código_aberto_gratuito.md
│   ├── pt_pt_software_de_erp_crm_de_código_aberto_gratuito.md
│   ├── ro_ro_software_erp_crm_open_source_gratuit.md
│   ├── ru_ru_бесплатное_открытое_программное_обеспечение_erp_crm.md
│   ├── sk_sk_zdarma_otvorene_zdrojove_erp_crm_software.md
│   ├── sl_si_brezplačni_odprtokodni_erp_crm_programski_oprema.md
│   ├── sr_rs_besplatni_otvoreni_izvor_erp_crm_softver.md
│   ├── sv_se_fri_öppen_källkods_erp_crm_programvara.md
│   ├── th_th_ฟรี_โปรแกรม_ตัวจัดการแหล่งข้อมูลโปรแกรม_ERP_CRM.md
│   ├── tr_tr_ücretsiz_açık_kaynak_erp_crm_yazılımı.md
│   ├── uk_ua_безкоштовне_відкрите_джерело_erp_crm_програмне_забезпечення.md
│   ├── ur_pk_مفت_کھولیں_سورس_erp_crm_سافٹ ویئر.md
│   ├── vi_vn_chương_trình_quản_lý_doanh_nghiệp_crm_nguồn_mở_miễn_phí.md
│   └── zh_cn_免费开源ERP CRM软件.md
└── frontend/
    ├── .eslintrc.js
    ├── .gitignore
    ├── .prettierignore
    ├── .prettierrc
    ├── .vscode/
    │   └── settings.json
    ├── README.md
    ├── index.html
    ├── jsconfig.json
    ├── package.json
    ├── public/
    │   └── robots.txt
    ├── rollup.config.js
    ├── src/
    │   ├── RootApp.jsx
    │   ├── apps/
    │   │   ├── ErpApp.jsx
    │   │   ├── Header/
    │   │   │   ├── HeaderContainer.jsx
    │   │   │   └── UpgradeButton.jsx
    │   │   ├── IdurarOs.jsx
    │   │   └── Navigation/
    │   │       └── NavigationContainer.jsx
    │   ├── auth/
    │   │   ├── auth.service.js
    │   │   └── index.js
    │   ├── components/
    │   │   ├── AutoCompleteAsync/
    │   │   │   └── index.jsx
    │   │   ├── CollapseBox/
    │   │   │   └── index.jsx
    │   │   ├── CreateForm/
    │   │   │   └── index.jsx
    │   │   ├── CrudModal/
    │   │   │   └── index.jsx
    │   │   ├── DataTable/
    │   │   │   └── DataTable.jsx
    │   │   ├── DeleteModal/
    │   │   │   └── index.jsx
    │   │   ├── IconMenu/
    │   │   │   └── index.jsx
    │   │   ├── Loading/
    │   │   │   └── index.jsx
    │   │   ├── MoneyInputFormItem/
    │   │   │   └── index.jsx
    │   │   ├── MultiStepSelectAsync/
    │   │   │   └── index.jsx
    │   │   ├── NotFound/
    │   │   │   └── index.jsx
    │   │   ├── Notification/
    │   │   │   └── index.jsx
    │   │   ├── PageLoader/
    │   │   │   └── index.jsx
    │   │   ├── ReadItem/
    │   │   │   └── index.jsx
    │   │   ├── SearchItem/
    │   │   │   └── index.jsx
    │   │   ├── SelectAsync/
    │   │   │   └── index.jsx
    │   │   ├── SelectTag/
    │   │   │   └── index.jsx
    │   │   ├── SidePanel/
    │   │   │   └── index.jsx
    │   │   ├── TabsContent/
    │   │   │   └── TabsContent.jsx
    │   │   ├── Tag/
    │   │   │   └── index.jsx
    │   │   ├── UpdateForm/
    │   │   │   └── index.jsx
    │   │   ├── Visibility/
    │   │   │   └── index.jsx
    │   │   └── outsideClick.js/
    │   │       ├── demo.js
    │   │       └── index.js
    │   ├── config/
    │   │   └── serverApiConfig.js
    │   ├── context/
    │   │   ├── adavancedCrud/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   ├── selectors.jsx
    │   │   │   └── types.jsx
    │   │   ├── appContext/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   └── types.jsx
    │   │   ├── crud/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   ├── selectors.jsx
    │   │   │   └── types.jsx
    │   │   ├── erp/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   ├── selectors.jsx
    │   │   │   └── types.jsx
    │   │   └── profileContext/
    │   │       ├── actions.jsx
    │   │       ├── index.jsx
    │   │       ├── reducer.jsx
    │   │       ├── selectors.jsx
    │   │       └── types.jsx
    │   ├── forms/
    │   │   ├── AdminForm.jsx
    │   │   ├── AdvancedSettingsForm.jsx
    │   │   ├── CurrencyForm.jsx
    │   │   ├── CustomerForm.jsx
    │   │   ├── DynamicForm/
    │   │   │   └── index.jsx
    │   │   ├── EmployeeForm.jsx
    │   │   ├── ForgetPasswordForm.jsx
    │   │   ├── InventoryForm.jsx
    │   │   ├── LeadForm.jsx
    │   │   ├── LoginForm.jsx
    │   │   ├── OrderForm.jsx
    │   │   ├── PaymentForm.jsx
    │   │   ├── PaymentModeForm.jsx
    │   │   ├── RegisterForm.jsx
    │   │   ├── ResetPasswordForm.jsx
    │   │   ├── TaxForm.jsx
    │   │   └── UpdateEmail.jsx
    │   ├── hooks/
    │   │   ├── useDebounce.jsx
    │   │   ├── useFetch.jsx
    │   │   ├── useMail.jsx
    │   │   ├── useNetwork.jsx
    │   │   ├── useOnFetch.jsx
    │   │   ├── useResponsive.jsx
    │   │   └── useTimeoutFn.jsx
    │   ├── layout/
    │   │   ├── AuthLayout/
    │   │   │   └── index.jsx
    │   │   ├── CrudLayout/
    │   │   │   └── index.jsx
    │   │   ├── DashboardLayout/
    │   │   │   └── index.jsx
    │   │   ├── DefaultLayout/
    │   │   │   └── index.jsx
    │   │   ├── ErpLayout/
    │   │   │   └── index.jsx
    │   │   ├── Footer/
    │   │   │   └── index.jsx
    │   │   ├── ProfileLayout/
    │   │   │   └── index.jsx
    │   │   ├── SettingsLayout/
    │   │   │   └── index.jsx
    │   │   └── index.jsx
    │   ├── locale/
    │   │   ├── Localization.jsx
    │   │   ├── antdLocale.js
    │   │   ├── coreTranslation.js
    │   │   ├── translation/
    │   │   │   ├── en_us.js
    │   │   │   ├── otherTranslation.js
    │   │   │   └── translation.js
    │   │   └── useLanguage.jsx
    │   ├── main.jsx
    │   ├── modules/
    │   │   ├── AuthModule/
    │   │   │   ├── SideContent.jsx
    │   │   │   └── index.jsx
    │   │   ├── CrudModule/
    │   │   │   └── CrudModule.jsx
    │   │   ├── DashboardModule/
    │   │   │   ├── components/
    │   │   │   │   ├── CustomerPreviewCard.jsx
    │   │   │   │   ├── PreviewCard.jsx
    │   │   │   │   ├── RecentTable/
    │   │   │   │   │   └── index.jsx
    │   │   │   │   └── SummaryCard.jsx
    │   │   │   └── index.jsx
    │   │   ├── ErpPanelModule/
    │   │   │   ├── CreateItem.jsx
    │   │   │   ├── DataTable.jsx
    │   │   │   ├── DeleteItem.jsx
    │   │   │   ├── ItemRow.jsx
    │   │   │   ├── ReadItem.jsx
    │   │   │   ├── SearchItem.jsx
    │   │   │   ├── UpdateItem.jsx
    │   │   │   └── index.jsx
    │   │   ├── InvoiceModule/
    │   │   │   ├── CreateInvoiceModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── Forms/
    │   │   │   │   └── InvoiceForm.jsx
    │   │   │   ├── InvoiceDataTableModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── ReadInvoiceModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── RecordPaymentModule/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── Payment.jsx
    │   │   │   │   │   └── RecordPayment.jsx
    │   │   │   │   └── index.jsx
    │   │   │   └── UpdateInvoiceModule/
    │   │   │       └── index.jsx
    │   │   ├── PaymentModule/
    │   │   │   ├── PaymentDataTableModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── ReadPaymentModule/
    │   │   │   │   ├── components/
    │   │   │   │   │   └── ReadItem.jsx
    │   │   │   │   └── index.jsx
    │   │   │   └── UpdatePaymentModule/
    │   │   │       ├── components/
    │   │   │       │   ├── Payment.jsx
    │   │   │       │   └── UpdatePayment.jsx
    │   │   │       └── index.jsx
    │   │   ├── ProfileModule/
    │   │   │   ├── components/
    │   │   │   │   ├── AdminInfo.jsx
    │   │   │   │   ├── PasswordModal.jsx
    │   │   │   │   ├── Profile.jsx
    │   │   │   │   ├── ProfileAdminForm.jsx
    │   │   │   │   ├── UpdateAdmin.jsx
    │   │   │   │   └── UploadImg.jsx
    │   │   │   └── index.jsx
    │   │   ├── QuoteModule/
    │   │   │   ├── CreateQuoteModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── Forms/
    │   │   │   │   └── QuoteForm.jsx
    │   │   │   ├── QuoteDataTableModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── ReadQuoteModule/
    │   │   │   │   └── index.jsx
    │   │   │   └── UpdateQuoteModule/
    │   │   │       └── index.jsx
    │   │   └── SettingModule/
    │   │       ├── CompanyLogoSettingsModule/
    │   │       │   ├── forms/
    │   │       │   │   └── AppSettingForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── CompanySettingsModule/
    │   │       │   ├── SettingsForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── FinanceSettingsModule/
    │   │       │   ├── SettingsForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── GeneralSettingsModule/
    │   │       │   ├── forms/
    │   │       │   │   └── GeneralSettingForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── MoneyFormatSettingsModule/
    │   │       │   ├── SettingsForm.jsx
    │   │       │   └── index.jsx
    │   │       └── components/
    │   │           ├── SetingsSection.jsx
    │   │           ├── UpdateSettingForm.jsx
    │   │           └── UpdateSettingModule.jsx
    │   ├── pages/
    │   │   ├── About.jsx
    │   │   ├── Customer/
    │   │   │   ├── config.js
    │   │   │   └── index.jsx
    │   │   ├── ForgetPassword.jsx
    │   │   ├── Invoice/
    │   │   │   ├── InvoiceCreate.jsx
    │   │   │   ├── InvoiceRead.jsx
    │   │   │   ├── InvoiceRecordPayment.jsx
    │   │   │   ├── InvoiceUpdate.jsx
    │   │   │   └── index.jsx
    │   │   ├── Login.jsx
    │   │   ├── Logout.jsx
    │   │   ├── NotFound.jsx
    │   │   ├── Payment/
    │   │   │   ├── PaymentRead.jsx
    │   │   │   ├── PaymentUpdate.jsx
    │   │   │   └── index.jsx
    │   │   ├── Profile.jsx
    │   │   ├── ResetPassword.jsx
    │   │   └── Settings/
    │   │       ├── CompanyLogoSettings.jsx
    │   │       ├── CompanySettings.jsx
    │   │       ├── FinanceSettings.jsx
    │   │       ├── GeneralSettings.jsx
    │   │       ├── MoneyFormatSettings.jsx
    │   │       └── Settings.jsx
    │   ├── redux/
    │   │   ├── adavancedCrud/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── auth/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── crud/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── erp/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── rootReducer.js
    │   │   ├── settings/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── store.js
    │   │   └── storePersist.js
    │   ├── request/
    │   │   ├── checkImage.js
    │   │   ├── codeMessage.js
    │   │   ├── errorHandler.js
    │   │   ├── index.js
    │   │   ├── request.js
    │   │   └── successHandler.js
    │   ├── router/
    │   │   ├── AppRouter.jsx
    │   │   ├── AuthRouter.jsx
    │   │   └── routes.jsx
    │   ├── settings/
    │   │   ├── index.jsx
    │   │   ├── useDate.jsx
    │   │   └── useMoney.jsx
    │   ├── style/
    │   │   ├── app.css
    │   │   └── partials/
    │   │       ├── auth.css
    │   │       ├── collapseBox.css
    │   │       ├── core.css
    │   │       ├── customAntd.css
    │   │       ├── erp.css
    │   │       ├── header.css
    │   │       ├── layout.css
    │   │       ├── navigation.css
    │   │       ├── rest.css
    │   │       ├── sidePanel.css
    │   │       └── transition.css
    │   └── utils/
    │       ├── calculate.js
    │       ├── color.js
    │       ├── countryList.js
    │       ├── currencyList.js
    │       ├── dataStructure.jsx
    │       ├── helpers.js
    │       ├── isBrowser.js
    │       ├── statusTagColor.js
    │       ├── tagColor.js
    │       └── valueType.js
    ├── temp.env
    └── vite.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/custom.md
================================================
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---




================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/pull_request_template.md
================================================
## Description

Please provide a brief description of the changes or additions made in this pull request.

## Related Issues

If this pull request is related to any issue(s), please list them here.

## Steps to Test

Provide steps on how to test the changes introduced in this pull request.

## Screenshots (if applicable)

If your changes include visual updates, it would be helpful to provide screenshots of the before and after.

## Checklist

- [ ] I have tested these changes
- [ ] I have updated the relevant documentation
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the codebase
- [ ] My changes generate no new warnings or errors
- [ ] The title of my pull request is clear and descriptive


================================================
FILE: .github/workflows/CODEOWNERS
================================================
# Default reviewers 
* @salahlalami @polymahh @onfranciis @Ando22 @Fernando7181

================================================
FILE: .github/workflows/codesee-arch-diagram.yml
================================================
# This workflow was added by CodeSee. Learn more at https://codesee.io/
# This is v2.0 of this workflow file
on:
  push:
    branches:
      - master
  pull_request_target:
    types: [opened, synchronize, reopened]

name: CodeSee

permissions: read-all

jobs:
  codesee:
    runs-on: ubuntu-latest
    continue-on-error: true
    name: Analyze the repo with CodeSee
    steps:
      - uses: Codesee-io/codesee-action@v2
        with:
          codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
          codesee-url: https://app.codesee.io


================================================
FILE: .github/workflows/github-repo-stats.yml
================================================
name: github-repo-stats

on:
  schedule:
    # Run this once per day, towards the end of the day for keeping the most
    # recent data point most meaningful (hours are interpreted in UTC).
    - cron: "50 23 * * *"
  workflow_dispatch: # Allow for running this manually.

jobs:
  j1:
    name: github-repo-stats
    runs-on: ubuntu-latest
    steps:
      - name: run-ghrs
        # Use latest release.
        uses: jgehrcke/github-repo-stats@RELEASE
        with:
          ghtoken: ${{ secrets.ghrs_github_api_token }}



================================================
FILE: CODE-OF-CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
50052356+idurar@users.noreply.github.com.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines

Welcome to the [idurar-erp-crm](<[idurar-erp-crm](https://github.com/idurar/idurar-erp-crm)>) repository! We're excited that you're interested in contributing. Please take a moment to review this document to ensure a smooth collaboration process.

## How to Contribute

### Reporting Issues

If you find a bug or have a suggestion for an enhancement :

- please make sure it was not asked before here [issues](https://github.com/idurar/idurar-erp-crm/issues).
- make sure it is not work in progress here [pull requests](https://github.com/idurar/idurar-erp-crm/pulls).
- you can then [create an issue](https://github.com/idurar/idurar-erp-crm/issues/new/choose) with the following information:
  - a short but descriptive title.
  - a detailed description of the issue or suggestion (if it is a bug include the steps to reproduce it).

### working on issues

- comment on issues you want to work on and we will assign you to it.
- we do accept pull requests even if you are not assigned to an issue but we prefer you to comment on the issue first.

### Submitting Pull Requests

1. Fork the repository and create your own branch from `dev` branch.
2. follow this format for naming branches:
   - `features/new-profile-page`
   - `issues/fix-authentication-issue`
3. Make sure your code follows our [Coding Guidelines](#coding-guidelines).
4. Commit your changes using clear and descriptive commit messages .
5. Push your changes to your forked repository.
6. Submit a pull request to the `dev` branch of this repository. Please include a detailed description of your changes.

We'll review your pull request as soon as possible. Feedback and suggestions are always welcome.

### Commit Guidelines

Commits should be as small as possible, while ensuring that each commit is
correct independently (i.e., each commit should compile and pass tests).
Please follow this commit format for your commit messages:

- `feat: add new profile page`
- `fix: resolve authentication issue`

### Coding Guidelines

- Use consistent coding style and follow best practices for readability.
- Write clear and concise code comments.
- Don't update dependencies (antd, redux, craco ... ) as it might break the project( we will update all dependencies soon ).
- Do not include changes that are not related to the issue at hand.
- Ensure your code has no conflicts and follows existing patterns.

### Questions

If you have any questions, feel free to reach out by creating an issue.

Thank you for contributing to [idurar-erp-crm](https://github.com/idurar/idurar-erp-crm) dont forget to give us a :star: !


================================================
FILE: INSTALLATION-INSTRUCTIONS.md
================================================
## Getting started

#### Step 1: Clone the repository

```bash
git clone https://github.com/idurar/idurar-erp-crm.git
```

```bash
cd idurar-erp-crm
```

#### Step 2: Create Your MongoDB Account and Database Cluster

- Create your own MongoDB account by visiting the MongoDB website and signing up for a new account.

- Create a new database or cluster by following the instructions provided in the MongoDB documentation. Remember to note down the "Connect to your application URI" for the database, as you will need it later. Also, make sure to change `<password>` with your own password

- add your current IP address to the MongoDB database's IP whitelist to allow connections (this is needed whenever your ip changes)

#### Step 3: Edit the Environment File

- Check a file named .env in the /backend directory.

  This file will store environment variables for the project to run.

#### Step 4: Update MongoDB URI

In the .env file, find the line that reads:

`DATABASE="your-mongodb-uri"`

Replace "your-mongodb-uri" with the actual URI of your MongoDB database.

#### Step 5: Install Backend Dependencies

In your terminal, navigate to the /backend directory

```bash
cd backend
```

the urn the following command to install the backend dependencies:

```bash
npm install
```

This command will install all the required packages specified in the package.json file.

#### Step 6: Run Setup Script

While still in the /backend directory of the project, execute the following command to run the setup script:

```bash
npm run setup
```

This setup script may perform necessary database migrations or any other initialization tasks required for the project.

#### Step 7: Run the Backend Server

In the same terminal, run the following command to start the backend server:

```bash
npm run dev
```

This command will start the backend server, and it will listen for incoming requests.

#### Step 8: Install Frontend Dependencies

Open a new terminal window , and run the following command to install the frontend dependencies:

```bash
cd frontend
```

```bash
npm install
```

#### Step 9: Run the Frontend Server

After installing the frontend dependencies, run the following command in the same terminal to start the frontend server:

```bash
npm run dev
```

This command will start the frontend server, and you'll be able to access the website on localhost:3000 in your web browser.

:exclamation: :warning:` If you encounter an OpenSSL error while running the frontend server, follow these additional steps:`

Reason behind error: This is caused by the node.js V17 compatible issues with OpenSSL, see [this](https://github.com/nodejs/node/issues/40547) and [this](https://github.com/webpack/webpack/issues/14532) issue on GitHub.


Try one of these and error will be solved

- > upgrade to Node.js v20.

- > Enable legacy OpenSSL provider

Here is how you can enable legacy OpenSSL provider

- On Unix-like (Linux, macOS, Git bash, etc.)

```bash
export NODE_OPTIONS=--openssl-legacy-provider
```

- On Windows command prompt:

```bash
set NODE_OPTIONS=--openssl-legacy-provider
```

- On PowerShell:

```bash
$env:NODE_OPTIONS = "--openssl-legacy-provider"
```

Here is [reference](https://github.com/webpack/webpack/issues/14532#issuecomment-947012063) about enabling legacy OpenSSL provider

After trying above solutions, run below command

```bash
npm run dev
```

> If you still facing issue, then follow [this stackoverflow thread](https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported). It has so many different types of opinions. You definitely have solution after going through the thread.

================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007

Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

                            Preamble

The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.

The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.

When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.

A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.

The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.

An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.

The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

0. Definitions.

"This License" refers to version 3 of the GNU Affero General Public License.

"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.

To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

A "covered work" means either the unmodified Program or a work based
on the Program.

To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

1. Source Code.

The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.

A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

The Corresponding Source for a work in source code form is that
same work.

2. Basic Permissions.

All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.

3. Protecting Users' Legal Rights From Anti-Circumvention Law.

No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

4. Conveying Verbatim Copies.

You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

5. Conveying Modified Source Versions.

You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

6. Conveying Non-Source Forms.

You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

7. Additional Terms.

"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

8. Termination.

You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

9. Acceptance Not Required for Having Copies.

You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

10. Automatic Licensing of Downstream Recipients.

Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.

An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

11. Patents.

A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".

A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

12. No Surrender of Others' Freedom.

If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

13. Remote Network Interaction; Use with the GNU General Public License.

Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.

Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.

14. Revised Versions of this License.

The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.

If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

15. Disclaimer of Warranty.

THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. Limitation of Liability.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

17. Interpretation of Sections 15 and 16.

If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.

You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.


================================================
FILE: README.md
================================================
<div align="center">
    <a href="https://www.idurarapp.com/">
  <img src="https://avatars.githubusercontent.com/u/50052356?s=200&v=4" width="128px" />
    </a>
    <h1>Open Source ERP / CRM Accounting Invoice Quote</h1>
    <p align="center">
        <p>IDURAR ERP CRM | Simple To Use</p>
    </p>
    

```
 Give a Star ⭐️ & Fork to this project ... Happy coding! 🤩`
```

IDURAR is Open Source ERP / CRM (Invoice / Quote / Accounting ) Based on Advanced Mern Stack (Node.js / Express.js / MongoDb / React.js ) with Ant Design (AntD) and Redux

</div>

**🚀 Self-hosted Entreprise Version** : [https://cloud.idurarapp.com](https://cloud.idurarapp.com)



## Features :

Invoice Management

Payment Management

Quote Management

Customer Management

Ant Design Framework(AntD) 🐜

Based on Mern Stack (Node.js / Express.js / MongoDb / React.js ) 👨‍💻

### May i can use IDURAR for Commercial use :

- Yes You can use IDURAR for free for personal or Commercial use.

## Our Sponsors

  <a href="https://m.do.co/c/4ead8370b905?ref=idurarapp.com">
    <img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_blue.svg" width="201px">
  </a>

#

<img width="1403" alt="Open Source ERP CRM" src="https://github.com/idurar/idurar-erp-crm/assets/136928179/a6712286-7ca6-4822-8902-fb7523533ee8">

## Free Open Source ERP / CRM App

IDURAR is Open "Fair-Code" Source ERP / CRM (Invoice / Inventory / Accounting / HR) Based on Mern Stack (Node.js / Express.js / MongoDb / React.js ) with Ant Design (AntD) and Redux


## Getting started

1.[Clone the repository](INSTALLATION-INSTRUCTIONS.md#step-1-clone-the-repository)

2.[Create Your MongoDB Account and Database Cluster](INSTALLATION-INSTRUCTIONS.md#Step-2-Create-Your-MongoDB-Account-and-Database-Cluster)

3.[Edit the Environment File](INSTALLATION-INSTRUCTIONS.md#Step-3-Edit-the-Environment-File)

4.[Update MongoDB URI](INSTALLATION-INSTRUCTIONS.md#Step-4-Update-MongoDB-URI)

5.[Install Backend Dependencies](INSTALLATION-INSTRUCTIONS.md#Step-5-Install-Backend-Dependencies)

6.[Run Setup Script](INSTALLATION-INSTRUCTIONS.md#Step-6-Run-Setup-Script)

7.[Run the Backend Server](INSTALLATION-INSTRUCTIONS.md#Step-7-Run-the-Backend-Server)

8.[Install Frontend Dependencies](INSTALLATION-INSTRUCTIONS.md#Step-8-Install-Frontend-Dependencies)

9.[Run the Frontend Server](INSTALLATION-INSTRUCTIONS.md#Step-9-Run-the-Frontend-Server)

## Contributing

1.[How to contribute](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#how-to-contribute)

2.[Reporting issues](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#reporting-issues)

3.[Working on issues ](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#working-on-issues)

4.[Submitting pull requests](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#submitting-pull-requests)

5.[Commit Guidelines](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#commit-guidelines)

6.[Coding Guidelines](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#coding-guidelines)

7.[Questions](https://github.com/idurar/idurar-erp-crm/blob/master/CONTRIBUTING.md#questions)


## Show your support

Dont forget to give a ⭐️ to this project ... Happy coding!

**🚀 Self-hosted Entreprise Version** : [https://cloud.idurarapp.com](https://cloud.idurarapp.com)

## License

IDURAR is Free Open Source Released under the GNU Affero General Public License v3.0.


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Releases

| Version | Supported          |
| ------- | ------------------ |
| 2.0.1   | :white_check_mark: |
| 2.0.0   | :white_check_mark: |

## Reporting a Vulnerability

Please do not open public github issues or pull requests on this repository for security-related matters. Instead, follow the responsible disclosure process outlined below.

### Scope

This security policy covers the security of this repository and its code. If you discover a security vulnerability related to this repository, please report it responsibly.

### Responsible Disclosure Process

#### Option 1: Reporting via Github Security Advisors

1. **Contact Us**: Submit your report to [https://github.com/idurar/idurar-erp-crm/security](https://github.com/idurar/idurar-erp-crm/security) with details of the vulnerability. Please provide a clear and concise description of the issue, any potential impact, and a step-by-step demonstration if possible. Please do not include sensitive information in your initial email.

2. **Confirmation**: We will acknowledge receipt of your report within [X] business days and provide an estimated timeline for when you can expect a response.

3. **Investigation**: We will investigate the issue, which may involve reproducing the vulnerability or seeking further information from you.

4. **Resolution**: Once the vulnerability is confirmed, we will work to address it promptly and develop a fix.

5. **Disclosure**: We will coordinate with you regarding the public disclosure of the vulnerability. We aim to release a security advisory with information about the issue and the fix.



### Safe Harbor

We consider security research conducted under this policy to be:

- Authorized concerning any applicable anti-hacking laws, and we won't initiate legal action against researchers for their findings.

- Subject to responsible disclosure, where we work with researchers to understand and address reported vulnerabilities before public disclosure.

We appreciate your contributions to the security of this project and community.

Thank you!


================================================
FILE: backend/.eslintrc.js
================================================
module.exports = {
  env: {
    browser: true,
    es2020: true,
    node: true,
  },
  extends: 'eslint:recommended',
  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
  },
  rules: {
    'no-console': 0,
  },
};


================================================
FILE: backend/.gitignore
================================================
node_modules/
*.zip
.DS_Store
.idea
notes.md
.env.local

*.pdf

================================================
FILE: backend/.prettierignore
================================================
# Ignore artifacts:
build
coverage
node_modules

================================================
FILE: backend/.prettierrc
================================================
{
  "printWidth": 100,
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}


================================================
FILE: backend/.vscode/settings.json
================================================
{
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}


================================================
FILE: backend/jsconfig.json
================================================
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@/*": ["./*"]
    }
  },
  "exclude": ["node_modules"]
}


================================================
FILE: backend/package.json
================================================
{
  "name": "idurar-erp-crm",
  "version": "4.1.0",
  "engines": {
    "npm": "10.2.4",
    "node": "20.9.0"
  },
  "scripts": {
    "start": "node src/server.js",
    "dev": "nodemon src/server.js --ignore public/",
    "production": "NODE_ENV=production",
    "setup": "node src/setup/setup.js",
    "upgrade": "node src/setup/upgrade.js",
    "reset": "node src/setup/reset.js"
  },
  "dependencies": {
    "@aws-sdk/client-s3": "^3.509.0",
    "bcryptjs": "^2.4.3",
    "compression": "^1.7.4",
    "cookie-parser": "^1.4.6",
    "cors": "^2.8.5",
    "currency.js": "2.0.4",
    "dotenv": "16.3.1",
    "express": "^4.18.2",
    "express-fileupload": "^1.4.3",
    "express-rate-limit": "^7.1.5",
    "glob": "10.3.10",
    "html-pdf": "^3.0.1",
    "joi": "^17.11.0",
    "jsonwebtoken": "^9.0.2",
    "lodash": "^4.17.21",
    "module-alias": "^2.2.3",
    "moment": "^2.30.1",
    "mongoose": "^8.1.1",
    "mongoose-autopopulate": "^1.1.0",
    "multer": "^1.4.4",
    "node-cache": "^5.1.2",
    "openai": "^4.27.0",
    "pug": "^3.0.2",
    "resend": "^2.0.0",
    "shortid": "^2.2.16",
    "transliteration": "^2.3.5"
  },
  "devDependencies": {
    "nodemon": "3.0.1"
  },
  "_moduleAliases": {
    "@": "src"
  },
  "main": "server.js",
  "author": "IDURAR",
  "email": "hello@idurarapp.com",
  "license": "Fair-code License",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/idurar/idurar-erp-crm/.git"
  },
  "bugs": {
    "url": "https://github.com/idurar/idurar-erp-crm//issues"
  },
  "homepage": "https://github.com/idurar/idurar-erp-crm/#readme"
}


================================================
FILE: backend/src/app.js
================================================
const express = require('express');

const cors = require('cors');
const compression = require('compression');

const cookieParser = require('cookie-parser');

const coreAuthRouter = require('./routes/coreRoutes/coreAuth');
const coreApiRouter = require('./routes/coreRoutes/coreApi');
const coreDownloadRouter = require('./routes/coreRoutes/coreDownloadRouter');
const corePublicRouter = require('./routes/coreRoutes/corePublicRouter');
const adminAuth = require('./controllers/coreControllers/adminAuth');

const errorHandlers = require('./handlers/errorHandlers');
const erpApiRouter = require('./routes/appRoutes/appApi');

const fileUpload = require('express-fileupload');
// create our Express app
const app = express();

app.use(
  cors({
    origin: true,
    credentials: true,
  })
);

app.use(cookieParser());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(compression());

// // default options
// app.use(fileUpload());

// Here our API Routes

app.use('/api', coreAuthRouter);
app.use('/api', adminAuth.isValidAuthToken, coreApiRouter);
app.use('/api', adminAuth.isValidAuthToken, erpApiRouter);
app.use('/download', coreDownloadRouter);
app.use('/public', corePublicRouter);

// If that above routes didnt work, we 404 them and forward to error handler
app.use(errorHandlers.notFound);

// production error handler
app.use(errorHandlers.productionErrors);

// done! we export it so we can start the site in start.js
module.exports = app;


================================================
FILE: backend/src/controllers/appControllers/clientController/index.js
================================================
const mongoose = require('mongoose');
const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');

const summary = require('./summary');

function modelController() {
  const Model = mongoose.model('Client');
  const methods = createCRUDController('Client');

  methods.summary = (req, res) => summary(Model, req, res);
  return methods;
}

module.exports = modelController();


================================================
FILE: backend/src/controllers/appControllers/clientController/summary.js
================================================
const mongoose = require('mongoose');
const moment = require('moment');

const InvoiceModel = mongoose.model('Invoice');

const summary = async (Model, req, res) => {
  let defaultType = 'month';
  const { type } = req.query;

  if (type && ['week', 'month', 'year'].includes(type)) {
    defaultType = type;
  } else if (type) {
    return res.status(400).json({
      success: false,
      result: null,
      message: 'Invalid type',
    });
  }

  const currentDate = moment();
  let startDate = currentDate.clone().startOf(defaultType);
  let endDate = currentDate.clone().endOf(defaultType);

  const pipeline = [
    {
      $facet: {
        totalClients: [
          {
            $match: {
              removed: false,
              enabled: true,
            },
          },
          {
            $count: 'count',
          },
        ],
        newClients: [
          {
            $match: {
              removed: false,
              created: { $gte: startDate.toDate(), $lte: endDate.toDate() },
              enabled: true,
            },
          },
          {
            $count: 'count',
          },
        ],
        activeClients: [
          {
            $lookup: {
              from: InvoiceModel.collection.name,
              localField: '_id', // Match _id from ClientModel
              foreignField: 'client', // Match client field in InvoiceModel
              as: 'invoice',
            },
          },
          {
            $match: {
              'invoice.removed': false,
            },
          },
          {
            $group: {
              _id: '$_id',
            },
          },
          {
            $count: 'count',
          },
        ],
      },
    },
  ];

  const aggregationResult = await Model.aggregate(pipeline);

  const result = aggregationResult[0];
  const totalClients = result.totalClients[0] ? result.totalClients[0].count : 0;
  const totalNewClients = result.newClients[0] ? result.newClients[0].count : 0;
  const activeClients = result.activeClients[0] ? result.activeClients[0].count : 0;

  const totalActiveClientsPercentage = totalClients > 0 ? (activeClients / totalClients) * 100 : 0;
  const totalNewClientsPercentage = totalClients > 0 ? (totalNewClients / totalClients) * 100 : 0;

  return res.status(200).json({
    success: true,
    result: {
      new: Math.round(totalNewClientsPercentage),
      active: Math.round(totalActiveClientsPercentage),
    },
    message: 'Successfully get summary of new clients',
  });
};

module.exports = summary;


================================================
FILE: backend/src/controllers/appControllers/index.js
================================================
const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');
const { routesList } = require('@/models/utils');

const { globSync } = require('glob');
const path = require('path');

const pattern = './src/controllers/appControllers/*/**/';
const controllerDirectories = globSync(pattern).map((filePath) => {
  return path.basename(filePath);
});

const appControllers = () => {
  const controllers = {};
  const hasCustomControllers = [];

  controllerDirectories.forEach((controllerName) => {
    try {
      const customController = require('@/controllers/appControllers/' + controllerName);

      if (customController) {
        hasCustomControllers.push(controllerName);
        controllers[controllerName] = customController;
      }
    } catch (err) {
      throw new Error(err.message);
    }
  });

  routesList.forEach(({ modelName, controllerName }) => {
    if (!hasCustomControllers.includes(controllerName)) {
      controllers[controllerName] = createCRUDController(modelName);
    }
  });

  return controllers;
};

module.exports = appControllers();


================================================
FILE: backend/src/controllers/appControllers/invoiceController/create.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Invoice');

const { calculate } = require('@/helpers');
const { increaseBySettingKey } = require('@/middlewares/settings');
const schema = require('./schemaValidate');

const create = async (req, res) => {
  let body = req.body;

  const { error, value } = schema.validate(body);
  if (error) {
    const { details } = error;
    return res.status(400).json({
      success: false,
      result: null,
      message: details[0]?.message,
    });
  }

  const { items = [], taxRate = 0, discount = 0 } = value;

  // default
  let subTotal = 0;
  let taxTotal = 0;
  let total = 0;

  //Calculate the items array with subTotal, total, taxTotal
  items.map((item) => {
    let total = calculate.multiply(item['quantity'], item['price']);
    //sub total
    subTotal = calculate.add(subTotal, total);
    //item total
    item['total'] = total;
  });
  taxTotal = calculate.multiply(subTotal, taxRate / 100);
  total = calculate.add(subTotal, taxTotal);

  body['subTotal'] = subTotal;
  body['taxTotal'] = taxTotal;
  body['total'] = total;
  body['items'] = items;

  let paymentStatus = calculate.sub(total, discount) === 0 ? 'paid' : 'unpaid';

  body['paymentStatus'] = paymentStatus;
  body['createdBy'] = req.admin._id;

  // Creating a new document in the collection
  const result = await new Model(body).save();
  const fileId = 'invoice-' + result._id + '.pdf';
  const updateResult = await Model.findOneAndUpdate(
    { _id: result._id },
    { pdf: fileId },
    {
      new: true,
    }
  ).exec();
  // Returning successfull response

  increaseBySettingKey({
    settingKey: 'last_invoice_number',
  });

  // Returning successfull response
  return res.status(200).json({
    success: true,
    result: updateResult,
    message: 'Invoice created successfully',
  });
};

module.exports = create;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/index.js
================================================
const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');
const methods = createCRUDController('Invoice');

const sendMail = require('./sendMail');
const create = require('./create');
const summary = require('./summary');
const update = require('./update');
const remove = require('./remove');
const paginatedList = require('./paginatedList');
const read = require('./read');

methods.mail = sendMail;
methods.create = create;
methods.update = update;
methods.delete = remove;
methods.summary = summary;
methods.list = paginatedList;
methods.read = read;

module.exports = methods;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/paginatedList.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Invoice');

const paginatedList = async (req, res) => {
  const page = req.query.page || 1;
  const limit = parseInt(req.query.items) || 10;
  const skip = page * limit - limit;

  const { sortBy = 'enabled', sortValue = -1, filter, equal } = req.query;

  const fieldsArray = req.query.fields ? req.query.fields.split(',') : [];

  let fields;

  fields = fieldsArray.length === 0 ? {} : { $or: [] };

  for (const field of fieldsArray) {
    fields.$or.push({ [field]: { $regex: new RegExp(req.query.q, 'i') } });
  }

  //  Query the database for a list of all results
  const resultsPromise = Model.find({
    removed: false,

    [filter]: equal,
    ...fields,
  })
    .skip(skip)
    .limit(limit)
    .sort({ [sortBy]: sortValue })
    .populate('createdBy', 'name')
    .exec();

  // Counting the total documents
  const countPromise = Model.countDocuments({
    removed: false,

    [filter]: equal,
    ...fields,
  });

  // Resolving both promises
  const [result, count] = await Promise.all([resultsPromise, countPromise]);
  // Calculating total pages
  const pages = Math.ceil(count / limit);

  // Getting Pagination Object
  const pagination = { page, pages, count };
  if (count > 0) {
    return res.status(200).json({
      success: true,
      result,
      pagination,
      message: 'Successfully found all documents',
    });
  } else {
    return res.status(203).json({
      success: true,
      result: [],
      pagination,
      message: 'Collection is Empty',
    });
  }
};

module.exports = paginatedList;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/read.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Invoice');

const read = async (req, res) => {
  // Find document by id
  const result = await Model.findOne({
    _id: req.params.id,
    removed: false,
  })
    .populate('createdBy', 'name')
    .exec();
  // If no results found, return document not found
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  } else {
    // Return success resposne
    return res.status(200).json({
      success: true,
      result,
      message: 'we found this document ',
    });
  }
};

module.exports = read;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/remove.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Invoice');
const ModelPayment = mongoose.model('Payment');

const remove = async (req, res) => {
  const deletedInvoice = await Model.findOneAndUpdate(
    {
      _id: req.params.id,
      removed: false,
    },
    {
      $set: {
        removed: true,
      },
    }
  ).exec();

  if (!deletedInvoice) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'Invoice not found',
    });
  }
  const paymentsInvoices = await ModelPayment.updateMany(
    { invoice: deletedInvoice._id },
    { $set: { removed: true } }
  );
  return res.status(200).json({
    success: true,
    result: deletedInvoice,
    message: 'Invoice deleted successfully',
  });
};

module.exports = remove;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/schemaValidate.js
================================================
const Joi = require('joi');
const schema = Joi.object({
  client: Joi.alternatives().try(Joi.string(), Joi.object()).required(),
  number: Joi.number().required(),
  year: Joi.number().required(),
  status: Joi.string().required(),
  notes: Joi.string().allow(''),
  expiredDate: Joi.date().required(),
  date: Joi.date().required(),
  // array cannot be empty
  items: Joi.array()
    .items(
      Joi.object({
        _id: Joi.string().allow('').optional(),
        itemName: Joi.string().required(),
        description: Joi.string().allow(''),
        quantity: Joi.number().required(),
        price: Joi.number().required(),
        total: Joi.number().required(),
      }).required()
    )
    .required(),
  taxRate: Joi.alternatives().try(Joi.number(), Joi.string()).required(),
});

module.exports = schema;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/sendMail.js
================================================
const fs = require('fs');

const mongoose = require('mongoose');

const mail = async (req, res) => {
  return res.status(200).json({
    success: true,
    result: null,
    message: 'Please Upgrade to Premium  Version to have full features',
  });
};

module.exports = mail;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/summary.js
================================================
const mongoose = require('mongoose');
const moment = require('moment');

const Model = mongoose.model('Invoice');

const { loadSettings } = require('@/middlewares/settings');

const summary = async (req, res) => {
  let defaultType = 'month';

  const { type } = req.query;

  const settings = await loadSettings();

  if (type) {
    if (['week', 'month', 'year'].includes(type)) {
      defaultType = type;
    } else {
      return res.status(400).json({
        success: false,
        result: null,
        message: 'Invalid type',
      });
    }
  }

  const currentDate = moment();
  let startDate = currentDate.clone().startOf(defaultType);
  let endDate = currentDate.clone().endOf(defaultType);

  const statuses = ['draft', 'pending', 'overdue', 'paid', 'unpaid', 'partially'];

  const response = await Model.aggregate([
    {
      $match: {
        removed: false,
        // date: {
        //   $gte: startDate.toDate(),
        //   $lte: endDate.toDate(),
        // },
      },
    },
    {
      $facet: {
        totalInvoice: [
          {
            $group: {
              _id: null,
              total: {
                $sum: '$total',
              },
              count: {
                $sum: 1,
              },
            },
          },
          {
            $project: {
              _id: 0,
              total: '$total',
              count: '$count',
            },
          },
        ],
        statusCounts: [
          {
            $group: {
              _id: '$status',
              count: {
                $sum: 1,
              },
            },
          },
          {
            $project: {
              _id: 0,
              status: '$_id',
              count: '$count',
            },
          },
        ],
        paymentStatusCounts: [
          {
            $group: {
              _id: '$paymentStatus',
              count: {
                $sum: 1,
              },
            },
          },
          {
            $project: {
              _id: 0,
              status: '$_id',
              count: '$count',
            },
          },
        ],
        overdueCounts: [
          {
            $match: {
              expiredDate: {
                $lt: new Date(),
              },
            },
          },
          {
            $group: {
              _id: '$status',
              count: {
                $sum: 1,
              },
            },
          },
          {
            $project: {
              _id: 0,
              status: '$_id',
              count: '$count',
            },
          },
        ],
      },
    },
  ]);

  let result = [];

  const totalInvoices = response[0].totalInvoice ? response[0].totalInvoice[0] : 0;
  const statusResult = response[0].statusCounts || [];
  const paymentStatusResult = response[0].paymentStatusCounts || [];
  const overdueResult = response[0].overdueCounts || [];

  const statusResultMap = statusResult.map((item) => {
    return {
      ...item,
      percentage: Math.round((item.count / totalInvoices.count) * 100),
    };
  });

  const paymentStatusResultMap = paymentStatusResult.map((item) => {
    return {
      ...item,
      percentage: Math.round((item.count / totalInvoices.count) * 100),
    };
  });

  const overdueResultMap = overdueResult.map((item) => {
    return {
      ...item,
      status: 'overdue',
      percentage: Math.round((item.count / totalInvoices.count) * 100),
    };
  });

  statuses.forEach((status) => {
    const found = [...paymentStatusResultMap, ...statusResultMap, ...overdueResultMap].find(
      (item) => item.status === status
    );
    if (found) {
      result.push(found);
    }
  });

  const unpaid = await Model.aggregate([
    {
      $match: {
        removed: false,

        // date: {
        //   $gte: startDate.toDate(),
        //   $lte: endDate.toDate(),
        // },
        paymentStatus: {
          $in: ['unpaid', 'partially'],
        },
      },
    },
    {
      $group: {
        _id: null,
        total_amount: {
          $sum: {
            $subtract: ['$total', '$credit'],
          },
        },
      },
    },
    {
      $project: {
        _id: 0,
        total_amount: '$total_amount',
      },
    },
  ]);

  const finalResult = {
    total: totalInvoices?.total,
    total_undue: unpaid.length > 0 ? unpaid[0].total_amount : 0,
    type,
    performance: result,
  };

  return res.status(200).json({
    success: true,
    result: finalResult,
    message: `Successfully found all invoices for the last ${defaultType}`,
  });
};

module.exports = summary;


================================================
FILE: backend/src/controllers/appControllers/invoiceController/update.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Invoice');

const custom = require('@/controllers/pdfController');

const { calculate } = require('@/helpers');
const schema = require('./schemaValidate');

const update = async (req, res) => {
  let body = req.body;

  const { error, value } = schema.validate(body);
  if (error) {
    const { details } = error;
    return res.status(400).json({
      success: false,
      result: null,
      message: details[0]?.message,
    });
  }

  const previousInvoice = await Model.findOne({
    _id: req.params.id,
    removed: false,
  });

  const { credit } = previousInvoice;

  const { items = [], taxRate = 0, discount = 0 } = req.body;

  if (items.length === 0) {
    return res.status(400).json({
      success: false,
      result: null,
      message: 'Items cannot be empty',
    });
  }

  // default
  let subTotal = 0;
  let taxTotal = 0;
  let total = 0;

  //Calculate the items array with subTotal, total, taxTotal
  items.map((item) => {
    let total = calculate.multiply(item['quantity'], item['price']);
    //sub total
    subTotal = calculate.add(subTotal, total);
    //item total
    item['total'] = total;
  });
  taxTotal = calculate.multiply(subTotal, taxRate / 100);
  total = calculate.add(subTotal, taxTotal);

  body['subTotal'] = subTotal;
  body['taxTotal'] = taxTotal;
  body['total'] = total;
  body['items'] = items;
  body['pdf'] = 'invoice-' + req.params.id + '.pdf';
  if (body.hasOwnProperty('currency')) {
    delete body.currency;
  }
  // Find document by id and updates with the required fields

  let paymentStatus =
    calculate.sub(total, discount) === credit ? 'paid' : credit > 0 ? 'partially' : 'unpaid';
  body['paymentStatus'] = paymentStatus;

  const result = await Model.findOneAndUpdate({ _id: req.params.id, removed: false }, body, {
    new: true, // return the new result instead of the old one
  }).exec();

  // Returning successfull response

  return res.status(200).json({
    success: true,
    result,
    message: 'we update this document ',
  });
};

module.exports = update;


================================================
FILE: backend/src/controllers/appControllers/paymentController/create.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Payment');
const Invoice = mongoose.model('Invoice');
const custom = require('@/controllers/pdfController');

const { calculate } = require('@/helpers');

const create = async (req, res) => {
  // Creating a new document in the collection
  if (req.body.amount === 0) {
    return res.status(202).json({
      success: false,
      result: null,
      message: `The Minimum Amount couldn't be 0`,
    });
  }

  const currentInvoice = await Invoice.findOne({
    _id: req.body.invoice,
    removed: false,
  });

  const {
    total: previousTotal,
    discount: previousDiscount,
    credit: previousCredit,
  } = currentInvoice;

  const maxAmount = calculate.sub(calculate.sub(previousTotal, previousDiscount), previousCredit);

  if (req.body.amount > maxAmount) {
    return res.status(202).json({
      success: false,
      result: null,
      message: `The Max Amount you can add is ${maxAmount}`,
    });
  }
  req.body['createdBy'] = req.admin._id;

  const result = await Model.create(req.body);

  const fileId = 'payment-' + result._id + '.pdf';
  const updatePath = await Model.findOneAndUpdate(
    {
      _id: result._id.toString(),
      removed: false,
    },
    { pdf: fileId },
    {
      new: true,
    }
  ).exec();
  // Returning successfull response

  const { _id: paymentId, amount } = result;
  const { id: invoiceId, total, discount, credit } = currentInvoice;

  let paymentStatus =
    calculate.sub(total, discount) === calculate.add(credit, amount)
      ? 'paid'
      : calculate.add(credit, amount) > 0
      ? 'partially'
      : 'unpaid';

  const invoiceUpdate = await Invoice.findOneAndUpdate(
    { _id: req.body.invoice },
    {
      $push: { payment: paymentId.toString() },
      $inc: { credit: amount },
      $set: { paymentStatus: paymentStatus },
    },
    {
      new: true, // return the new result instead of the old one
      runValidators: true,
    }
  ).exec();

  return res.status(200).json({
    success: true,
    result: updatePath,
    message: 'Payment Invoice created successfully',
  });
};

module.exports = create;


================================================
FILE: backend/src/controllers/appControllers/paymentController/index.js
================================================
const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');
const methods = createCRUDController('Payment');

const create = require('./create');
const summary = require('./summary');
const update = require('./update');
const remove = require('./remove');
const sendMail = require('./sendMail');

methods.mail = sendMail;
methods.create = create;
methods.update = update;
methods.delete = remove;
methods.summary = summary;

module.exports = methods;


================================================
FILE: backend/src/controllers/appControllers/paymentController/remove.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Payment');
const Invoice = mongoose.model('Invoice');

const remove = async (req, res) => {
  // Find document by id and updates with the required fields
  const previousPayment = await Model.findOne({
    _id: req.params.id,
    removed: false,
  });

  if (!previousPayment) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  }

  const { _id: paymentId, amount: previousAmount } = previousPayment;
  const { id: invoiceId, total, discount, credit: previousCredit } = previousPayment.invoice;

  // Find the document by id and delete it
  let updates = {
    removed: true,
  };
  // Find the document by id and delete it
  const result = await Model.findOneAndUpdate(
    { _id: req.params.id, removed: false },
    { $set: updates },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();
  // If no results found, return document not found

  let paymentStatus =
    total - discount === previousCredit - previousAmount
      ? 'paid'
      : previousCredit - previousAmount > 0
      ? 'partially'
      : 'unpaid';

  const updateInvoice = await Invoice.findOneAndUpdate(
    { _id: invoiceId },
    {
      $pull: {
        payment: paymentId,
      },
      $inc: { credit: -previousAmount },
      $set: {
        paymentStatus: paymentStatus,
      },
    },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();

  return res.status(200).json({
    success: true,
    result,
    message: 'Successfully Deleted the document ',
  });
};
module.exports = remove;


================================================
FILE: backend/src/controllers/appControllers/paymentController/sendMail.js
================================================
const mail = async (req, res) => {
  return res.status(200).json({
    success: true,
    result: null,
    message: 'Please Upgrade to Premium  Version to have full features',
  });
};

module.exports = mail;


================================================
FILE: backend/src/controllers/appControllers/paymentController/summary.js
================================================
const mongoose = require('mongoose');
const moment = require('moment');

const Model = mongoose.model('Payment');
const { loadSettings } = require('@/middlewares/settings');

const summary = async (req, res) => {
  let defaultType = 'month';

  const { type } = req.query;

  const settings = await loadSettings();

  if (type) {
    if (['week', 'month', 'year'].includes(type)) {
      defaultType = type;
    } else {
      return res.status(400).json({
        success: false,
        result: null,
        message: 'Invalid type',
      });
    }
  }

  const currentDate = moment();
  let startDate = currentDate.clone().startOf(defaultType);
  let endDate = currentDate.clone().endOf(defaultType);

  // get total amount of invoices
  const result = await Model.aggregate([
    {
      $match: {
        removed: false,

        // date: {
        //   $gte: startDate.toDate(),
        //   $lte: endDate.toDate(),
        // },
      },
    },
    {
      $group: {
        _id: null, // Group all documents into a single group
        count: {
          $sum: 1,
        },
        total: {
          $sum: '$amount',
        },
      },
    },
    {
      $project: {
        _id: 0, // Exclude _id from the result
        count: 1,
        total: 1,
      },
    },
  ]);

  return res.status(200).json({
    success: true,
    result: result.length > 0 ? result[0] : { count: 0, total: 0 },
    message: `Successfully fetched the summary of payment invoices for the last ${defaultType}`,
  });
};

module.exports = summary;


================================================
FILE: backend/src/controllers/appControllers/paymentController/update.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Payment');
const Invoice = mongoose.model('Invoice');
const custom = require('@/controllers/pdfController');

const { calculate } = require('@/helpers');

const update = async (req, res) => {
  if (req.body.amount === 0) {
    return res.status(202).json({
      success: false,
      result: null,
      message: `The Minimum Amount couldn't be 0`,
    });
  }
  // Find document by id and updates with the required fields
  const previousPayment = await Model.findOne({
    _id: req.params.id,
    removed: false,
  });

  const { amount: previousAmount } = previousPayment;
  const { id: invoiceId, total, discount, credit: previousCredit } = previousPayment.invoice;

  const { amount: currentAmount } = req.body;

  const changedAmount = calculate.sub(currentAmount, previousAmount);
  const maxAmount = calculate.sub(total, calculate.add(discount, previousCredit));

  if (changedAmount > maxAmount) {
    return res.status(202).json({
      success: false,
      result: null,
      message: `The Max Amount you can add is ${maxAmount + previousAmount}`,
      error: `The Max Amount you can add is ${maxAmount + previousAmount}`,
    });
  }

  let paymentStatus =
    calculate.sub(total, discount) === calculate.add(previousCredit, changedAmount)
      ? 'paid'
      : calculate.add(previousCredit, changedAmount) > 0
      ? 'partially'
      : 'unpaid';

  const updatedDate = new Date();
  const updates = {
    number: req.body.number,
    date: req.body.date,
    amount: req.body.amount,
    paymentMode: req.body.paymentMode,
    ref: req.body.ref,
    description: req.body.description,
    updated: updatedDate,
  };

  const result = await Model.findOneAndUpdate(
    { _id: req.params.id, removed: false },
    { $set: updates },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();

  const updateInvoice = await Invoice.findOneAndUpdate(
    { _id: result.invoice._id.toString() },
    {
      $inc: { credit: changedAmount },
      $set: {
        paymentStatus: paymentStatus,
      },
    },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();

  return res.status(200).json({
    success: true,
    result,
    message: 'Successfully updated the Payment ',
  });
};

module.exports = update;


================================================
FILE: backend/src/controllers/coreControllers/adminAuth/index.js
================================================
const createAuthMiddleware = require('@/controllers/middlewaresControllers/createAuthMiddleware');
module.exports = createAuthMiddleware('Admin');


================================================
FILE: backend/src/controllers/coreControllers/adminController/index.js
================================================
const createUserController = require('@/controllers/middlewaresControllers/createUserController');
module.exports = createUserController('Admin');


================================================
FILE: backend/src/controllers/coreControllers/settingController/index.js
================================================
const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');
const crudController = createCRUDController('Setting');

const listBySettingKey = require('./listBySettingKey');
const readBySettingKey = require('./readBySettingKey');
const updateBySettingKey = require('./updateBySettingKey');
const updateManySetting = require('./updateManySetting');
const listAll = require('./listAll');

const settingMethods = {
  read: crudController.read,
  create: crudController.create,
  update: crudController.update,
  list: crudController.list,
  filter: crudController.filter,
  search: crudController.search,
  listAll: listAll,
  listBySettingKey,
  readBySettingKey,
  updateBySettingKey,
  updateManySetting,
};

module.exports = settingMethods;


================================================
FILE: backend/src/controllers/coreControllers/settingController/listAll.js
================================================
const mongoose = require('mongoose');
const Model = mongoose.model('Setting');

const listAll = async (req, res) => {
  const sort = parseInt(req.query.sort) || 'desc';

  //  Query the database for a list of all results
  const result = await Model.find({
    removed: false,
    isPrivate: false,
  }).sort({ created: sort });

  if (result.length > 0) {
    return res.status(200).json({
      success: true,
      result,
      message: 'Successfully found all documents',
    });
  } else {
    return res.status(203).json({
      success: false,
      result: [],
      message: 'Collection is Empty',
    });
  }
};

module.exports = listAll;


================================================
FILE: backend/src/controllers/coreControllers/settingController/listBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const listBySettingKey = async (req, res) => {
  // Find document by id

  const settingKeyArray = req.query.settingKeyArray ? req.query.settingKeyArray.split(',') : [];

  const settingsToShow = { $or: [] };

  if (settingKeyArray.length === 0) {
    return res
      .status(202)
      .json({
        success: false,
        result: [],
        message: 'Please provide settings you need',
      })
      .end();
  }

  for (const settingKey of settingKeyArray) {
    settingsToShow.$or.push({ settingKey });
  }

  let results = await Model.find({
    ...settingsToShow,
  }).where('removed', false);

  // If no results found, return document not found
  if (results.length >= 1) {
    return res.status(200).json({
      success: true,
      result: results,
      message: 'Successfully found all documents',
    });
  } else {
    return res
      .status(202)
      .json({
        success: false,
        result: [],
        message: 'No document found by this request',
      })
      .end();
  }
};

module.exports = listBySettingKey;


================================================
FILE: backend/src/controllers/coreControllers/settingController/readBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const readBySettingKey = async (req, res) => {
  // Find document by id
  const settingKey = req.params.settingKey || undefined;

  if (!settingKey) {
    return res.status(202).json({
      success: false,
      result: null,
      message: 'No settingKey provided ',
    });
  }

  const result = await Model.findOne({
    settingKey,
  });

  // If no results found, return document not found
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found by this settingKey: ' + settingKey,
    });
  } else {
    // Return success resposne
    return res.status(200).json({
      success: true,
      result,
      message: 'we found this document by this settingKey: ' + settingKey,
    });
  }
};

module.exports = readBySettingKey;


================================================
FILE: backend/src/controllers/coreControllers/settingController/updateBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const updateBySettingKey = async (req, res) => {
  const settingKey = req.params.settingKey || undefined;

  if (!settingKey) {
    return res.status(202).json({
      success: false,
      result: null,
      message: 'No settingKey provided ',
    });
  }
  const { settingValue } = req.body;

  if (!settingValue) {
    return res.status(202).json({
      success: false,
      result: null,
      message: 'No settingValue provided ',
    });
  }
  const result = await Model.findOneAndUpdate(
    { settingKey },
    {
      settingValue,
    },
    {
      new: true, // return the new result instead of the old one
      runValidators: true,
    }
  ).exec();
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found by this settingKey: ' + settingKey,
    });
  } else {
    return res.status(200).json({
      success: true,
      result,
      message: 'we update this document by this settingKey: ' + settingKey,
    });
  }
};

module.exports = updateBySettingKey;


================================================
FILE: backend/src/controllers/coreControllers/settingController/updateManySetting.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const updateManySetting = async (req, res) => {
  // req/body = [{settingKey:"",settingValue}]
  let settingsHasError = false;
  const updateDataArray = [];
  const { settings } = req.body;

  for (const setting of settings) {
    if (!setting.hasOwnProperty('settingKey') || !setting.hasOwnProperty('settingValue')) {
      settingsHasError = true;
      break;
    }

    const { settingKey, settingValue } = setting;

    updateDataArray.push({
      updateOne: {
        filter: { settingKey: settingKey },
        update: { settingValue: settingValue },
      },
    });
  }

  if (updateDataArray.length === 0) {
    return res.status(202).json({
      success: false,
      result: null,
      message: 'No settings provided ',
    });
  }
  if (settingsHasError) {
    return res.status(202).json({
      success: false,
      result: null,
      message: 'Settings provided has Error',
    });
  }
  const result = await Model.bulkWrite(updateDataArray);

  if (!result || result.nMatched < 1) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No settings found by to update',
    });
  } else {
    return res.status(200).json({
      success: true,
      result: [],
      message: 'we update all settings',
    });
  }
};

module.exports = updateManySetting;


================================================
FILE: backend/src/controllers/coreControllers/setup.js
================================================
require('dotenv').config({ path: '.env' });
require('dotenv').config({ path: '.env.local' });
const { globSync } = require('glob');
const fs = require('fs');
const { generate: uniqueId } = require('shortid');

const mongoose = require('mongoose');

const setup = async (req, res) => {
  const Admin = mongoose.model('Admin');
  const AdminPassword = mongoose.model('AdminPassword');
  const Setting = mongoose.model('Setting');

  const PaymentMode = mongoose.model('PaymentMode');
  const Taxes = mongoose.model('Taxes');

  const newAdminPassword = new AdminPassword();

  const { name, email, password, language, timezone, country, config = {} } = req.body;

  const objectSchema = Joi.object({
    name: Joi.string().required(),
    email: Joi.string()
      .email({ tlds: { allow: true } })
      .required(),
    password: Joi.string().required(),
  });

  const { error, value } = objectSchema.validate({ name, email, password });
  if (error) {
    return res.status(409).json({
      success: false,
      result: null,
      error: error,
      message: 'Invalid/Missing credentials.',
      errorMessage: error.message,
    });
  }

  const salt = uniqueId();

  const passwordHash = newAdminPassword.generateHash(salt, password);

  const accountOwnner = {
    email,
    name,
    role: 'owner',
  };
  const result = await new Admin(accountOwnner).save();

  const AdminPasswordData = {
    password: passwordHash,
    emailVerified: true,
    salt: salt,
    user: result._id,
  };
  await new AdminPassword(AdminPasswordData).save();

  const settingData = [];

  const settingsFiles = globSync('./src/setup/defaultSettings/**/*.json');

  for (const filePath of settingsFiles) {
    const file = JSON.parse(fs.readFileSync(filePath, 'utf-8'));

    const settingsToUpdate = {
      idurar_app_email: email,
      idurar_app_company_email: email,
      idurar_app_timezone: timezone,
      idurar_app_country: country,
      idurar_app_language: language || 'en_us',
    };

    const newSettings = file.map((x) => {
      const settingValue = settingsToUpdate[x.settingKey];
      return settingValue ? { ...x, settingValue } : { ...x };
    });

    settingData.push(...newSettings);
  }

  await Setting.insertMany(settingData);

  await Taxes.insertMany([{ taxName: 'Tax 0%', taxValue: '0', isDefault: true }]);

  await PaymentMode.insertMany([
    {
      name: 'Default Payment',
      description: 'Default Payment Mode (Cash , Wire Transfer)',
      isDefault: true,
    },
  ]);

  return res.status(200).json({
    success: true,
    result: {},
    message: 'Successfully IDURAR App Setup',
  });
};

module.exports = setup;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/authUser.js
================================================
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const authUser = async (req, res, { user, databasePassword, password, UserPasswordModel }) => {
  const isMatch = await bcrypt.compare(databasePassword.salt + password, databasePassword.password);

  if (!isMatch)
    return res.status(403).json({
      success: false,
      result: null,
      message: 'Invalid credentials.',
    });

  if (isMatch === true) {
    const token = jwt.sign(
      {
        id: user._id,
      },
      process.env.JWT_SECRET,
      { expiresIn: req.body.remember ? 365 * 24 + 'h' : '24h' }
    );

    await UserPasswordModel.findOneAndUpdate(
      { user: user._id },
      { $push: { loggedSessions: token } },
      {
        new: true,
      }
    ).exec();

    // .cookie(`token_${user.cloud}`, token, {
    //     maxAge: req.body.remember ? 365 * 24 * 60 * 60 * 1000 : null,
    //     sameSite: 'None',
    //     httpOnly: true,
    //     secure: true,
    //     domain: req.hostname,
    //     path: '/',
    //     Partitioned: true,
    //   })
    res.status(200).json({
      success: true,
      result: {
        _id: user._id,
        name: user.name,
        surname: user.surname,
        role: user.role,
        email: user.email,
        photo: user.photo,
        token: token,
        maxAge: req.body.remember ? 365 : null,
      },
      message: 'Successfully login user',
    });
  } else {
    return res.status(403).json({
      success: false,
      result: null,
      message: 'Invalid credentials.',
    });
  }
};

module.exports = authUser;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/checkAndCorrectURL.js
================================================
function checkAndCorrectURL(url) {
  // detect if it has http or https:
  const hasHttps = url.startsWith('https://');

  // Remove "http://" or "https://" if present
  url = url.replace(/^https?:\/\//i, '');

  // Remove trailing slashes
  url = url.replace(/\/+$/, '');

  const httpType = hasHttps ? 'https://' : 'http://';
  return httpType + url;
}

module.exports = checkAndCorrectURL;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/forgetPassword.js
================================================
const Joi = require('joi');

const mongoose = require('mongoose');

const checkAndCorrectURL = require('./checkAndCorrectURL');
const sendMail = require('./sendMail');
const shortid = require('shortid');
const { loadSettings } = require('@/middlewares/settings');

const { useAppSettings } = require('@/settings');

const forgetPassword = async (req, res, { userModel }) => {
  const UserPassword = mongoose.model(userModel + 'Password');
  const User = mongoose.model(userModel);
  const { email } = req.body;

  // validate
  const objectSchema = Joi.object({
    email: Joi.string()
      .email({ tlds: { allow: true } })
      .required(),
  });

  const { error, value } = objectSchema.validate({ email });
  if (error) {
    return res.status(409).json({
      success: false,
      result: null,
      error: error,
      message: 'Invalid email.',
      errorMessage: error.message,
    });
  }

  const user = await User.findOne({ email: email, removed: false });
  const databasePassword = await UserPassword.findOne({ user: user._id, removed: false });

  // console.log(user);
  if (!user)
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No account with this email has been registered.',
    });

  const resetToken = shortid.generate();
  await UserPassword.findOneAndUpdate(
    { user: user._id },
    { resetToken },
    {
      new: true,
    }
  ).exec();

  const settings = useAppSettings();
  const idurar_app_email = settings['idurar_app_email'];
  const idurar_base_url = settings['idurar_base_url'];

  const url = checkAndCorrectURL(idurar_base_url);

  const link = url + '/resetpassword/' + user._id + '/' + resetToken;

  await sendMail({
    email,
    name: user.name,
    link,
    subject: 'Reset your password | idurar',
    idurar_app_email,
    type: 'passwordVerfication',
  });

  return res.status(200).json({
    success: true,
    result: null,
    message: 'Check your email inbox , to reset your password',
  });
};

module.exports = forgetPassword;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/index.js
================================================
const isValidAuthToken = require('./isValidAuthToken');
const login = require('./login');
const logout = require('./logout');
const forgetPassword = require('./forgetPassword');
const resetPassword = require('./resetPassword');

const createAuthMiddleware = (userModel) => {
  let authMethods = {};

  authMethods.isValidAuthToken = (req, res, next) =>
    isValidAuthToken(req, res, next, {
      userModel,
    });

  authMethods.login = (req, res) =>
    login(req, res, {
      userModel,
    });

  authMethods.forgetPassword = (req, res) =>
    forgetPassword(req, res, {
      userModel,
    });

  authMethods.resetPassword = (req, res) =>
    resetPassword(req, res, {
      userModel,
    });

  authMethods.logout = (req, res) =>
    logout(req, res, {
      userModel,
    });
  return authMethods;
};

module.exports = createAuthMiddleware;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/isValidAuthToken.js
================================================
const jwt = require('jsonwebtoken');

const mongoose = require('mongoose');

const isValidAuthToken = async (req, res, next, { userModel, jwtSecret = 'JWT_SECRET' }) => {
  try {
    const UserPassword = mongoose.model(userModel + 'Password');
    const User = mongoose.model(userModel);

    // const token = req.cookies[`token_${cloud._id}`];
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1]; // Extract the token

    if (!token)
      return res.status(401).json({
        success: false,
        result: null,
        message: 'No authentication token, authorization denied.',
        jwtExpired: true,
      });

    const verified = jwt.verify(token, process.env[jwtSecret]);

    if (!verified)
      return res.status(401).json({
        success: false,
        result: null,
        message: 'Token verification failed, authorization denied.',
        jwtExpired: true,
      });

    const userPasswordPromise = UserPassword.findOne({ user: verified.id, removed: false });
    const userPromise = User.findOne({ _id: verified.id, removed: false });

    const [user, userPassword] = await Promise.all([userPromise, userPasswordPromise]);

    if (!user)
      return res.status(401).json({
        success: false,
        result: null,
        message: "User doens't Exist, authorization denied.",
        jwtExpired: true,
      });

    const { loggedSessions } = userPassword;

    if (!loggedSessions.includes(token))
      return res.status(401).json({
        success: false,
        result: null,
        message: 'User is already logout try to login, authorization denied.',
        jwtExpired: true,
      });
    else {
      const reqUserName = userModel.toLowerCase();
      req[reqUserName] = user;
      next();
    }
  } catch (error) {
    return res.status(500).json({
      success: false,
      result: null,
      message: error.message,
      error: error,
      controller: 'isValidAuthToken',
      jwtExpired: true,
    });
  }
};

module.exports = isValidAuthToken;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/login.js
================================================
const Joi = require('joi');

const mongoose = require('mongoose');

const authUser = require('./authUser');

const login = async (req, res, { userModel }) => {
  const UserPasswordModel = mongoose.model(userModel + 'Password');
  const UserModel = mongoose.model(userModel);
  const { email, password } = req.body;

  // validate
  const objectSchema = Joi.object({
    email: Joi.string()
      .email({ tlds: { allow: true } })
      .required(),
    password: Joi.string().required(),
  });

  const { error, value } = objectSchema.validate({ email, password });
  if (error) {
    return res.status(409).json({
      success: false,
      result: null,
      error: error,
      message: 'Invalid/Missing credentials.',
      errorMessage: error.message,
    });
  }

  const user = await UserModel.findOne({ email: email, removed: false });

  // console.log(user);
  if (!user)
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No account with this email has been registered.',
    });

  const databasePassword = await UserPasswordModel.findOne({ user: user._id, removed: false });

  if (!user.enabled)
    return res.status(409).json({
      success: false,
      result: null,
      message: 'Your account is disabled, contact your account adminstrator',
    });

  //  authUser if your has correct password
  authUser(req, res, {
    user,
    databasePassword,
    password,
    UserPasswordModel,
  });
};

module.exports = login;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/logout.js
================================================
const mongoose = require('mongoose');

const logout = async (req, res, { userModel }) => {
  const UserPassword = mongoose.model(userModel + 'Password');

  // const token = req.cookies[`token_${cloud._id}`];

  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1]; // Extract the token

  if (token)
    await UserPassword.findOneAndUpdate(
      { user: req.admin._id },
      { $pull: { loggedSessions: token } },
      {
        new: true,
      }
    ).exec();
  else
    await UserPassword.findOneAndUpdate(
      { user: req.admin._id },
      { loggedSessions: [] },
      {
        new: true,
      }
    ).exec();

  return res.json({
    success: true,
    result: {},
    message: 'Successfully logout',
  });
};

module.exports = logout;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/resetPassword.js
================================================
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const Joi = require('joi');
const mongoose = require('mongoose');

const shortid = require('shortid');

const resetPassword = async (req, res, { userModel }) => {
  const UserPassword = mongoose.model(userModel + 'Password');
  const User = mongoose.model(userModel);
  const { password, userId, resetToken } = req.body;

  const databasePassword = await UserPassword.findOne({ user: userId, removed: false });
  const user = await User.findOne({ _id: userId, removed: false }).exec();

  if (!user.enabled)
    return res.status(409).json({
      success: false,
      result: null,
      message: 'Your account is disabled, contact your account adminstrator',
    });

  if (!databasePassword || !user)
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No account with this email has been registered.',
    });

  const isMatch = resetToken === databasePassword.resetToken;
  if (!isMatch || databasePassword.resetToken === undefined || databasePassword.resetToken === null)
    return res.status(403).json({
      success: false,
      result: null,
      message: 'Invalid reset token',
    });

  // validate
  const objectSchema = Joi.object({
    password: Joi.string().required(),
    userId: Joi.string().required(),
    resetToken: Joi.string().required(),
  });

  const { error, value } = objectSchema.validate({ password, userId, resetToken });
  if (error) {
    return res.status(409).json({
      success: false,
      result: null,
      error: error,
      message: 'Invalid reset password object',
      errorMessage: error.message,
    });
  }

  const salt = shortid.generate();
  const hashedPassword = bcrypt.hashSync(salt + password);
  const emailToken = shortid.generate();

  const token = jwt.sign(
    {
      id: userId,
    },
    process.env.JWT_SECRET,
    { expiresIn: '24h' }
  );

  await UserPassword.findOneAndUpdate(
    { user: userId },
    {
      $push: { loggedSessions: token },
      password: hashedPassword,
      salt: salt,
      emailToken: emailToken,
      resetToken: shortid.generate(),
      emailVerified: true,
    },
    {
      new: true,
    }
  ).exec();

  if (
    resetToken === databasePassword.resetToken &&
    databasePassword.resetToken !== undefined &&
    databasePassword.resetToken !== null
  )
    //  .cookie(`token_${user.cloud}`, token, {
    //       maxAge: 24 * 60 * 60 * 1000,
    //       sameSite: 'None',
    //       httpOnly: true,
    //       secure: true,
    //       domain: req.hostname,
    //       path: '/',
    //       Partitioned: true,
    //     })
    return res.status(200).json({
      success: true,
      result: {
        _id: user._id,
        name: user.name,
        surname: user.surname,
        role: user.role,
        email: user.email,
        photo: user.photo,
        token: token,
        maxAge: req.body.remember ? 365 : null,
      },
      message: 'Successfully resetPassword user',
    });
};

module.exports = resetPassword;


================================================
FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/sendMail.js
================================================
const { passwordVerfication } = require('@/emailTemplate/emailVerfication');

const { Resend } = require('resend');

const sendMail = async ({
  email,
  name,
  link,
  idurar_app_email,
  subject = 'Verify your email | idurar',
  type = 'emailVerfication',
  emailToken,
}) => {
  const resend = new Resend(process.env.RESEND_API);

  const { data } = await resend.emails.send({
    from: idurar_app_email,
    to: email,
    subject,
    html: passwordVerfication({ name, link }),
  });

  return data;
};

module.exports = sendMail;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/create.js
================================================
const create = async (Model, req, res) => {
  // Creating a new document in the collection
  req.body.removed = false;
  const result = await new Model({
    ...req.body,
  }).save();

  // Returning successfull response
  return res.status(200).json({
    success: true,
    result,
    message: 'Successfully Created the document in Model ',
  });
};

module.exports = create;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/filter.js
================================================
const filter = async (Model, req, res) => {
  if (req.query.filter === undefined || req.query.equal === undefined) {
    return res.status(403).json({
      success: false,
      result: null,
      message: 'filter not provided correctly',
    });
  }
  const result = await Model.find({
    removed: false,
  })
    .where(req.query.filter)
    .equals(req.query.equal)
    .exec();
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  } else {
    // Return success resposne
    return res.status(200).json({
      success: true,
      result,
      message: 'Successfully found all documents  ',
    });
  }
};

module.exports = filter;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/index.js
================================================
const { modelsFiles } = require('@/models/utils');

const mongoose = require('mongoose');

const create = require('./create');
const read = require('./read');
const update = require('./update');
const remove = require('./remove');
const search = require('./search');
const filter = require('./filter');
const summary = require('./summary');
const listAll = require('./listAll');
const paginatedList = require('./paginatedList');

const createCRUDController = (modelName) => {
  if (!modelsFiles.includes(modelName)) {
    throw new Error(`Model ${modelName} does not exist`);
  }

  const Model = mongoose.model(modelName);
  let crudMethods = {
    create: (req, res) => create(Model, req, res),
    read: (req, res) => read(Model, req, res),
    update: (req, res) => update(Model, req, res),
    delete: (req, res) => remove(Model, req, res),
    list: (req, res) => paginatedList(Model, req, res),
    listAll: (req, res) => listAll(Model, req, res),
    search: (req, res) => search(Model, req, res),
    filter: (req, res) => filter(Model, req, res),
    summary: (req, res) => summary(Model, req, res),
  };
  return crudMethods;
};

module.exports = createCRUDController;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/listAll.js
================================================
const listAll = async (Model, req, res) => {
  const sort = req.query.sort || 'desc';
  const enabled = req.query.enabled || undefined;

  //  Query the database for a list of all results

  let result;
  if (enabled === undefined) {
    result = await Model.find({
      removed: false,
    })
      .sort({ created: sort })
      .populate()
      .exec();
  } else {
    result = await Model.find({
      removed: false,
      enabled: enabled,
    })
      .sort({ created: sort })
      .populate()
      .exec();
  }

  if (result.length > 0) {
    return res.status(200).json({
      success: true,
      result,
      message: 'Successfully found all documents',
    });
  } else {
    return res.status(203).json({
      success: false,
      result: [],
      message: 'Collection is Empty',
    });
  }
};

module.exports = listAll;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/paginatedList.js
================================================
const paginatedList = async (Model, req, res) => {
  const page = req.query.page || 1;
  const limit = parseInt(req.query.items) || 10;
  const skip = page * limit - limit;

  const { sortBy = 'enabled', sortValue = -1, filter, equal } = req.query;

  const fieldsArray = req.query.fields ? req.query.fields.split(',') : [];

  let fields;

  fields = fieldsArray.length === 0 ? {} : { $or: [] };

  for (const field of fieldsArray) {
    fields.$or.push({ [field]: { $regex: new RegExp(req.query.q, 'i') } });
  }

  // Build filter condition safely: reject MongoDB operators in values
  let filterCondition = {};
  if (filter && equal !== undefined) {
    if (typeof equal === 'object') {
      return res.status(400).json({
        success: false,
        result: [],
        message: 'Invalid filter value',
      });
    }
    filterCondition = { [filter]: equal };
  }

  //  Query the database for a list of all results
  const resultsPromise = Model.find({
    removed: false,
    ...filterCondition,
    ...fields,
  })
    .skip(skip)
    .limit(limit)
    .sort({ [sortBy]: sortValue })
    .populate()
    .exec();

  // Counting the total documents
  const countPromise = Model.countDocuments({
    removed: false,
    ...filterCondition,
    ...fields,
  });
  // Resolving both promises
  const [result, count] = await Promise.all([resultsPromise, countPromise]);

  // Calculating total pages
  const pages = Math.ceil(count / limit);

  // Getting Pagination Object
  const pagination = { page, pages, count };
  if (count > 0) {
    return res.status(200).json({
      success: true,
      result,
      pagination,
      message: 'Successfully found all documents',
    });
  } else {
    return res.status(203).json({
      success: true,
      result: [],
      pagination,
      message: 'Collection is Empty',
    });
  }
};

module.exports = paginatedList;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/read.js
================================================
const read = async (Model, req, res) => {
  // Find document by id
  const result = await Model.findOne({
    _id: req.params.id,
    removed: false,
  }).exec();
  // If no results found, return document not found
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  } else {
    // Return success resposne
    return res.status(200).json({
      success: true,
      result,
      message: 'we found this document ',
    });
  }
};

module.exports = read;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/remove.js
================================================
const remove = async (Model, req, res) => {
  // Find the document by id and delete it
  let updates = {
    removed: true,
  };
  // Find the document by id and delete it
  const result = await Model.findOneAndUpdate(
    {
      _id: req.params.id,
    },
    { $set: updates },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();
  // If no results found, return document not found
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  } else {
    return res.status(200).json({
      success: true,
      result,
      message: 'Successfully Deleted the document ',
    });
  }
};

module.exports = remove;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/search.js
================================================
const search = async (Model, req, res) => {
  // console.log(req.query.fields)
  // if (req.query.q === undefined || req.query.q.trim() === '') {
  //   return res
  //     .status(202)
  //     .json({
  //       success: false,
  //       result: [],
  //       message: 'No document found by this request',
  //     })
  //     .end();
  // }
  const fieldsArray = req.query.fields ? req.query.fields.split(',') : ['name'];

  const fields = { $or: [] };

  for (const field of fieldsArray) {
    fields.$or.push({ [field]: { $regex: new RegExp(req.query.q, 'i') } });
  }
  // console.log(fields)

  let results = await Model.find({
    ...fields,
  })

    .where('removed', false)
    .limit(20)
    .exec();

  if (results.length >= 1) {
    return res.status(200).json({
      success: true,
      result: results,
      message: 'Successfully found all documents',
    });
  } else {
    return res
      .status(202)
      .json({
        success: false,
        result: [],
        message: 'No document found by this request',
      })
      .end();
  }
};

module.exports = search;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/summary.js
================================================
const summary = async (Model, req, res) => {
  //  Query the database for a list of all results
  const countPromise = Model.countDocuments({
    removed: false,
  });

  const resultsPromise = await Model.countDocuments({
    removed: false,
  })
    .where(req.query.filter)
    .equals(req.query.equal)
    .exec();
  // Resolving both promises
  const [countFilter, countAllDocs] = await Promise.all([resultsPromise, countPromise]);

  if (countAllDocs.length > 0) {
    return res.status(200).json({
      success: true,
      result: { countFilter, countAllDocs },
      message: 'Successfully count all documents',
    });
  } else {
    return res.status(203).json({
      success: false,
      result: [],
      message: 'Collection is Empty',
    });
  }
};

module.exports = summary;


================================================
FILE: backend/src/controllers/middlewaresControllers/createCRUDController/update.js
================================================
const update = async (Model, req, res) => {
  // Find document by id and updates with the required fields
  req.body.removed = false;
  const result = await Model.findOneAndUpdate(
    {
      _id: req.params.id,
      removed: false,
    },
    req.body,
    {
      new: true, // return the new result instead of the old one
      runValidators: true,
    }
  ).exec();
  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  } else {
    return res.status(200).json({
      success: true,
      result,
      message: 'we update this document ',
    });
  }
};

module.exports = update;


================================================
FILE: backend/src/controllers/middlewaresControllers/createUserController/index.js
================================================
const read = require('./read');
const updateProfile = require('./updateProfile');

const updatePassword = require('./updatePassword');
const updateProfilePassword = require('./updateProfilePassword');

const createUserController = (userModel) => {
  let userController = {};

  userController.updateProfile = (req, res) => updateProfile(userModel, req, res);
  userController.updatePassword = (req, res) => updatePassword(userModel, req, res);
  userController.updateProfilePassword = (req, res) => updateProfilePassword(userModel, req, res);

  userController.read = (req, res) => read(userModel, req, res);

  return userController;
};

module.exports = createUserController;


================================================
FILE: backend/src/controllers/middlewaresControllers/createUserController/read.js
================================================
const mongoose = require('mongoose');

const read = async (userModel, req, res) => {
  const User = mongoose.model(userModel);

  // Find document by id
  const tmpResult = await User.findOne({
    _id: req.params.id,
    removed: false,
  }).exec();
  // If no results found, return document not found
  if (!tmpResult) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No document found ',
    });
  } else {
    // Return success resposne
    let result = {
      _id: tmpResult._id,
      enabled: tmpResult.enabled,
      email: tmpResult.email,
      name: tmpResult.name,
      surname: tmpResult.surname,
      photo: tmpResult.photo,
      role: tmpResult.role,
    };

    return res.status(200).json({
      success: true,
      result,
      message: 'we found this document ',
    });
  }
};

module.exports = read;


================================================
FILE: backend/src/controllers/middlewaresControllers/createUserController/updatePassword.js
================================================
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const { generate: uniqueId } = require('shortid');

const updatePassword = async (userModel, req, res) => {
  const UserPassword = mongoose.model(userModel + 'Password');

  const reqUserName = userModel.toLowerCase();
  const userProfile = req[reqUserName];

  let { password } = req.body;

  if (password.length < 8)
    return res.status(400).json({
      msg: 'The password needs to be at least 8 characters long.',
    });

  // Find document by id and updates with the required fields

  if (userProfile.email === 'admin@admin.com') {
    return res.status(403).json({
      success: false,
      result: null,
      message: "you couldn't update demo password",
    });
  }

  const salt = uniqueId();

  const passwordHash = bcrypt.hashSync(salt + password);

  const UserPasswordData = {
    password: passwordHash,
    salt: salt,
  };

  const resultPassword = await UserPassword.findOneAndUpdate(
    { user: req.params.id, removed: false },
    { $set: UserPasswordData },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();

  // Code to handle the successful response

  if (!resultPassword) {
    return res.status(403).json({
      success: false,
      result: null,
      message: "User Password couldn't save correctly",
    });
  }

  return res.status(200).json({
    success: true,
    result: {},
    message: 'we update the password by this id: ' + userProfile._id,
  });
};

module.exports = updatePassword;


================================================
FILE: backend/src/controllers/middlewaresControllers/createUserController/updateProfile.js
================================================
const mongoose = require('mongoose');

const updateProfile = async (userModel, req, res) => {
  const User = mongoose.model(userModel);

  const reqUserName = userModel.toLowerCase();
  const userProfile = req[reqUserName];

  // Get token from Authorization header
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (userProfile.email === 'admin@demo.com') {
    return res.status(403).json({
      success: false,
      result: null,
      message: "you couldn't update demo informations",
    });
  }

  let updates = req.body.photo
    ? {
        email: req.body.email,
        name: req.body.name,
        surname: req.body.surname,
        photo: req.body.photo,
      }
    : {
        email: req.body.email,
        name: req.body.name,
        surname: req.body.surname,
      };
  // Find document by id and updates with the required fields
  const result = await User.findOneAndUpdate(
    { _id: userProfile._id, removed: false },
    { $set: updates },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();

  if (!result) {
    return res.status(404).json({
      success: false,
      result: null,
      message: 'No profile found by this id: ' + userProfile._id,
    });
  }
  return res.status(200).json({
    success: true,
    result: {
      _id: result?._id,
      enabled: result?.enabled,
      email: result?.email,
      name: result?.name,
      surname: result?.surname,
      photo: result?.photo,
      role: result?.role,
      token
    },
    message: 'we update this profile by this id: ' + userProfile._id,
  });
};

module.exports = updateProfile;


================================================
FILE: backend/src/controllers/middlewaresControllers/createUserController/updateProfilePassword.js
================================================
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const { generate: uniqueId } = require('shortid');

const updateProfilePassword = async (userModel, req, res) => {
  const UserPassword = mongoose.model(userModel + 'Password');

  const reqUserName = userModel.toLowerCase();
  const userProfile = req[reqUserName];
  let { password, passwordCheck } = req.body;

  if (!password || !passwordCheck)
    return res.status(400).json({ msg: 'Not all fields have been entered.' });

  if (password.length < 8)
    return res.status(400).json({
      msg: 'The password needs to be at least 8 characters long.',
    });

  if (password !== passwordCheck)
    return res.status(400).json({ msg: 'Enter the same password twice for verification.' });

  // Find document by id and updates with the required fields

  const salt = uniqueId();

  const passwordHash = bcrypt.hashSync(salt + password);

  const UserPasswordData = {
    password: passwordHash,
    salt: salt,
  };

  if (userProfile.email === 'admin@admin.com') {
    return res.status(403).json({
      success: false,
      result: null,
      message: "you couldn't update demo password",
    });
  }
  const resultPassword = await UserPassword.findOneAndUpdate(
    { user: userProfile._id, removed: false },
    { $set: UserPasswordData },
    {
      new: true, // return the new result instead of the old one
    }
  ).exec();

  if (!resultPassword) {
    return res.status(403).json({
      success: false,
      result: null,
      message: "User Password couldn't save correctly",
    });
  }

  return res.status(200).json({
    success: true,
    result: {},
    message: 'we update the password by this id: ' + userProfile._id,
  });
};

module.exports = updateProfilePassword;


================================================
FILE: backend/src/controllers/pdfController/index.js
================================================
const pug = require('pug');
const fs = require('fs');
const moment = require('moment');
let pdf = require('html-pdf');
const { listAllSettings, loadSettings } = require('@/middlewares/settings');
const { getData } = require('@/middlewares/serverData');
const useLanguage = require('@/locale/useLanguage');
const { useMoney, useDate } = require('@/settings');

const pugFiles = ['invoice', 'offer', 'quote', 'payment'];

require('dotenv').config({ path: '.env' });
require('dotenv').config({ path: '.env.local' });

exports.generatePdf = async (
  modelName,
  info = { filename: 'pdf_file', format: 'A5', targetLocation: '' },
  result,
  callback
) => {
  try {
    const { targetLocation } = info;

    // if PDF already exists, then delete it and create a new PDF
    if (fs.existsSync(targetLocation)) {
      fs.unlinkSync(targetLocation);
    }

    // render pdf html

    if (pugFiles.includes(modelName.toLowerCase())) {
      // Compile Pug template

      const settings = await loadSettings();
      const selectedLang = settings['idurar_app_language'];
      const translate = useLanguage({ selectedLang });

      const {
        currency_symbol,
        currency_position,
        decimal_sep,
        thousand_sep,
        cent_precision,
        zero_format,
      } = settings;

      const { moneyFormatter } = useMoney({
        settings: {
          currency_symbol,
          currency_position,
          decimal_sep,
          thousand_sep,
          cent_precision,
          zero_format,
        },
      });
      const { dateFormat } = useDate({ settings });

      settings.public_server_file = process.env.PUBLIC_SERVER_FILE;

      const htmlContent = pug.renderFile('src/pdf/' + modelName + '.pug', {
        model: result,
        settings,
        translate,
        dateFormat,
        moneyFormatter,
        moment: moment,
      });

      pdf
        .create(htmlContent, {
          format: info.format,
          orientation: 'portrait',
          border: '10mm',
        })
        .toFile(targetLocation, function (error) {
          if (error) throw new Error(error);
          if (callback) callback();
        });
    }
  } catch (error) {
    throw new Error(error);
  }
};


================================================
FILE: backend/src/emailTemplate/SendEmailTemplate.js
================================================
exports.SendInvoice = ({ title = 'Invoice from Idurar', name = '', time = new Date() }) => {
  return `
    <div>

        <head data-id="__react-email-head">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>${title}</title>
        </head>
        <div id="__react-email-preview" style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">Your invoice - Idurar<div> ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏</div>
        </div>

        <body data-id="__react-email-body">
            <h2 data-id="react-email-heading">${title}</h2>
            <hr data-id="react-email-hr" style="width:100%;border:none;border-top:1px solid #eaeaea" />
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Hello ${name},</p>
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Here&#x27;s the invoice you requested at ${time}</p>
        </body>
    </div>
    `;
};

exports.SendQuote = ({ title = 'Quote from Idurar', name = '', time = new Date() }) => {
  return `
    <div>

        <head data-id="__react-email-head">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>${title}</title>
        </head>
        <div id="__react-email-preview" style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">Your quote - Idurar<div> ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏</div>
        </div>

        <body data-id="__react-email-body">
            <h2 data-id="react-email-heading">${title}</h2>
            <hr data-id="react-email-hr" style="width:100%;border:none;border-top:1px solid #eaeaea" />
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Hello ${name},</p>
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Here&#x27;s the quote you requested at ${time}</p>
        </body>
    </div>
    `;
};

exports.SendOffer = ({ title = 'Offer from Idurar', name = '', time = new Date() }) => {
  return `
    <div>

        <head data-id="__react-email-head">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>${title}</title>
        </head>
        <div id="__react-email-preview" style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">Your offer - Idurar<div> ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏</div>
        </div>

        <body data-id="__react-email-body">
            <h2 data-id="react-email-heading">${title}</h2>
            <hr data-id="react-email-hr" style="width:100%;border:none;border-top:1px solid #eaeaea" />
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Hello ${name},</p>
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Here&#x27;s the offer you requested at ${time}</p>
        </body>
    </div>
    `;
};

exports.SendPaymentReceipt = ({
  title = 'Payment Receipt from Idurar',
  name = '',
  time = new Date(),
}) => {
  return `
    <div>

        <head data-id="__react-email-head">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>${title}</title>
        </head>
        <div id="__react-email-preview" style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">Your Payment Receipt - Idurar<div> ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏</div>
        </div>

        <body data-id="__react-email-body">
            <h2 data-id="react-email-heading">${title}</h2>
            <hr data-id="react-email-hr" style="width:100%;border:none;border-top:1px solid #eaeaea" />
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Hello ${name},</p>
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Here&#x27;s the Payment Receipt you requested at ${time}</p>
        </body>
    </div>
    `;
};


================================================
FILE: backend/src/emailTemplate/emailVerfication.js
================================================
exports.passwordVerfication = ({
  title = 'Reset your Password',
  name = '',
  link = '',
  time = new Date(),
}) => {
  return `
    <div>

        <head data-id="__react-email-head">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>${title}</title>
        </head>
        <div id="__react-email-preview" style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">Reset your Password<div> ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏</div>
        </div>

        <body data-id="__react-email-body">
            <h2 data-id="react-email-heading">${title}</h2>
            <hr data-id="react-email-hr" style="width:100%;border:none;border-top:1px solid #eaeaea" />
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">Hello ${name},</p>
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0">We have received a request to reset the password for your account on IDURAR. To proceed with the password reset, please click on the link provided below:</p>
            <p data-id="react-email-text" style="font-size:14px;line-height:24px;margin:16px 0"><a href="${link}">${link}</a></p>
            
           
        </body>
    </div>
    `;
};


================================================
FILE: backend/src/handlers/downloadHandler/downloadPdf.js
================================================
const custom = require('@/controllers/pdfController');
const mongoose = require('mongoose');

module.exports = downloadPdf = async (req, res, { directory, id }) => {
  try {
    const modelName = directory.slice(0, 1).toUpperCase() + directory.slice(1);
    if (mongoose.models[modelName]) {
      const Model = mongoose.model(modelName);
      const result = await Model.findOne({
        _id: id,
      }).exec();

      // Throw error if no result
      if (!result) {
        throw { name: 'ValidationError' };
      }

      // Continue process if result is returned

      const fileId = modelName.toLowerCase() + '-' + result._id + '.pdf';
      const folderPath = modelName.toLowerCase();
      const targetLocation = `src/public/download/${folderPath}/${fileId}`;
      await custom.generatePdf(
        modelName,
        { filename: folderPath, format: 'A4', targetLocation },
        result,
        async () => {
          return res.download(targetLocation, (error) => {
            if (error)
              return res.status(500).json({
                success: false,
                result: null,
                message: "Couldn't find file",
                error: error.message,
              });
          });
        }
      );
    } else {
      return res.status(404).json({
        success: false,
        result: null,
        message: `Model '${modelName}' does not exist`,
      });
    }
  } catch (error) {
    // If error is thrown by Mongoose due to required validations
    if (error.name == 'ValidationError') {
      return res.status(400).json({
        success: false,
        result: null,
        error: error.message,
        message: 'Required fields are not supplied',
      });
    } else if (error.name == 'BSONTypeError') {
      // If error is thrown by Mongoose due to invalid ID
      return res.status(400).json({
        success: false,
        result: null,
        error: error.message,
        message: 'Invalid ID',
      });
    } else {
      // Server Error
      return res.status(500).json({
        success: false,
        result: null,
        error: error.message,
        message: error.message,
        controller: 'downloadPDF.js',
      });
    }
  }
};


================================================
FILE: backend/src/handlers/errorHandlers.js
================================================
/*
  Catch Errors Handler

  With async/await, you need some way to catch errors
  Instead of using try{} catch(e) {} in each controller, we wrap the function in
  catchErrors(), catch any errors they throw, and pass it along to our express middleware with next()
*/

exports.catchErrors = (fn) => {
  return function (req, res, next) {
    return fn(req, res, next).catch((error) => {
      if (error.name == 'ValidationError') {
        return res.status(400).json({
          success: false,
          result: null,
          message: 'Required fields are not supplied',
          controller: fn.name,
          error: error,
        });
      } else {
        // Server Error
        return res.status(500).json({
          success: false,
          result: null,
          message: error.message,
          controller: fn.name,
          error: error,
        });
      }
    });
  };
};

/*
  Not Found Error Handler

  If we hit a route that is not found, we mark it as 404 and pass it along to the next error handler to display
*/
exports.notFound = (req, res, next) => {
  return res.status(404).json({
    success: false,
    message: "Api url doesn't exist ",
  });
};

/*
  Development Error Handler

  In development we show good error messages so if we hit a syntax error or any other previously un-handled error, we can show good info on what happened
*/
exports.developmentErrors = (error, req, res, next) => {
  error.stack = error.stack || '';
  const errorDetails = {
    message: error.message,
    status: error.status,
    stackHighlighted: error.stack.replace(/[a-z_-\d]+.js:\d+:\d+/gi, '<mark>$&</mark>'),
  };

  return res.status(500).json({
    success: false,
    message: error.message,
    error: error,
  });
};

/*
  Production Error Handler

  No stacktraces are leaked to admin
*/
exports.productionErrors = (error, req, res, next) => {
  return res.status(500).json({
    success: false,
    message: error.message,
    error: error,
  });
};


================================================
FILE: backend/src/helpers.js
================================================
/*
  This is a file of data and helper functions that we can expose and use in our templating function
*/

// FS is a built in module to node that let's us read files from the system we're running on
const fs = require('fs');

const currency = require('currency.js');

// moment.js is a handy library for displaying dates. We need this in our templates to display things like "Posted 5 minutes ago"
exports.moment = require('moment');

// Making a static map is really long - this is a handy helper function to make one

// inserting an SVG
exports.icon = (name) => {
  try {
    return fs.readFileSync(`./public/images/icons/${name}.svg`);
  } catch (error) {
    return null;
  }
};

exports.image = (name) => fs.readFileSync(`./public/images/photos/${name}.jpg`);

// Some details about the site
exports.siteName = `Express.js / MongoBD / Rest Api`;

exports.timeRange = (start, end, format, interval) => {
  if (format == undefined) {
    format = 'HH:mm';
  }

  if (interval == undefined) {
    interval = 60;
  }
  interval = interval > 0 ? interval : 60;

  const range = [];
  while (moment(start).isBefore(moment(end))) {
    range.push(moment(start).format(format));
    start = moment(start).add(interval, 'minutes');
  }
  return range;
};

exports.calculate = {
  add: (firstValue, secondValue) => {
    return currency(firstValue).add(secondValue).value;
  },
  sub: (firstValue, secondValue) => {
    return currency(firstValue).subtract(secondValue).value;
  },
  multiply: (firstValue, secondValue) => {
    return currency(firstValue).multiply(secondValue).value;
  },
  divide: (firstValue, secondValue) => {
    return currency(firstValue).divide(secondValue).value;
  },
};


================================================
FILE: backend/src/locale/languages.js
================================================
module.exports = [];


================================================
FILE: backend/src/locale/translation/en_us.js
================================================
module.exports = {
  sign_up: 'Sign Up',
  manage_your_company_with: 'Manage Your Company With',
  all_in_one_tool: 'All In One Tool',
  run_and_scale_your_erp_crm_apps: 'Run And Scale Your Erp Crm Apps',
  easily_add_and_manage_your_services: 'Easily Add And Manage Your Services',
  it_brings_together_your_invoice_clients_and_leads:
    'It Brings Together Your Invoice Clients And Leads',
  select_language: 'Select Language',
  register: 'Register',
  or: 'Or',
  already_have_account_login: 'Already Have Account Login',
  name: 'Name',
  email: 'Email',
  password: 'Password',
  country: 'Country',
  afghanistan: 'Afghanistan',
  albania: 'Albania',
  algeria: 'Algeria',
  andorra: 'Andorra',
  angola: 'Angola',
  anguilla: 'Anguilla',
  argentina: 'Argentina',
  armenia: 'Armenia',
  aruba: 'Aruba',
  australia: 'Australia',
  austria: 'Austria',
  azerbaijan: 'Azerbaijan',
  bahamas: 'Bahamas',
  bahrain: 'Bahrain',
  bangladesh: 'Bangladesh',
  barbados: 'Barbados',
  belarus: 'Belarus',
  belgium: 'Belgium',
  belize: 'Belize',
  benin: 'Benin',
  bermuda: 'Bermuda',
  bhutan: 'Bhutan',
  bolivia: 'Bolivia',
  bosnia_and_herzegovina: 'Bosnia And Herzegovina',
  botswana: 'Botswana',
  brazil: 'Brazil',
  brunei_darussalam: 'Brunei Darussalam',
  bulgaria: 'Bulgaria',
  burkina_faso: 'Burkina Faso',
  burundi: 'Burundi',
  cabo_verde: 'Cabo Verde',
  cambodia: 'Cambodia',
  cameroon: 'Cameroon',
  canada: 'Canada',
  central_african_republic: 'Central African Republic',
  chad: 'Chad',
  chile: 'Chile',
  china: 'China',
  colombia: 'Colombia',
  comoros: 'Comoros',
  congo: 'Congo',
  costa_rica: 'Costa Rica',
  croatia: 'Croatia',
  cuba: 'Cuba',
  cyprus: 'Cyprus',
  czechia: 'Czechia',
  cote_d_ivoire: 'Cote D Ivoire',
  denmark: 'Denmark',
  djibouti: 'Djibouti',
  dominica: 'Dominica',
  dominican_republic: 'Dominican Republic',
  ecuador: 'Ecuador',
  egypt: 'Egypt',
  el_salvador: 'El Salvador',
  eritrea: 'Eritrea',
  estonia: 'Estonia',
  eswatini: 'Eswatini',
  ethiopia: 'Ethiopia',
  fiji: 'Fiji',
  finland: 'Finland',
  france: 'France',
  gabon: 'Gabon',
  gambia: 'Gambia',
  georgia: 'Georgia',
  germany: 'Germany',
  ghana: 'Ghana',
  gibraltar: 'Gibraltar',
  greece: 'Greece',
  greenland: 'Greenland',
  guadeloupe: 'Guadeloupe',
  guam: 'Guam',
  guatemala: 'Guatemala',
  guernsey: 'Guernsey',
  guinea: 'Guinea',
  guinea_bissau: 'Guinea Bissau',
  guyana: 'Guyana',
  haiti: 'Haiti',
  honduras: 'Honduras',
  hong_kong: 'Hong Kong',
  hungary: 'Hungary',
  iceland: 'Iceland',
  india: 'India',
  indonesia: 'Indonesia',
  iran: 'Iran',
  iraq: 'Iraq',
  ireland: 'Ireland',
  israel: 'Israel',
  italy: 'Italy',
  jamaica: 'Jamaica',
  japan: 'Japan',
  jordan: 'Jordan',
  kazakhstan: 'Kazakhstan',
  kenya: 'Kenya',
  korea: 'Korea',
  kuwait: 'Kuwait',
  kyrgyzstan: 'Kyrgyzstan',
  latvia: 'Latvia',
  lebanon: 'Lebanon',
  lesotho: 'Lesotho',
  liberia: 'Liberia',
  libya: 'Libya',
  liechtenstein: 'Liechtenstein',
  lithuania: 'Lithuania',
  luxembourg: 'Luxembourg',
  madagascar: 'Madagascar',
  malawi: 'Malawi',
  malaysia: 'Malaysia',
  maldives: 'Maldives',
  mali: 'Mali',
  malta: 'Malta',
  martinique: 'Martinique',
  mauritania: 'Mauritania',
  mauritius: 'Mauritius',
  mexico: 'Mexico',
  moldova: 'Moldova',
  monaco: 'Monaco',
  mongolia: 'Mongolia',
  montenegro: 'Montenegro',
  montserrat: 'Montserrat',
  morocco: 'Morocco',
  mozambique: 'Mozambique',
  myanmar: 'Myanmar',
  namibia: 'Namibia',
  nepal: 'Nepal',
  netherlands: 'Netherlands',
  new_caledonia: 'New Caledonia',
  new_zealand: 'New Zealand',
  nicaragua: 'Nicaragua',
  niger: 'Niger',
  nigeria: 'Nigeria',
  norway: 'Norway',
  oman: 'Oman',
  pakistan: 'Pakistan',
  palestine: 'Palestine',
  panama: 'Panama',
  papua_new_guinea: 'Papua New Guinea',
  paraguay: 'Paraguay',
  peru: 'Peru',
  philippines: 'Philippines',
  poland: 'Poland',
  portugal: 'Portugal',
  puerto_rico: 'Puerto Rico',
  qatar: 'Qatar',
  macedonia: 'Macedonia',
  romania: 'Romania',
  russia: 'Russia',
  rwanda: 'Rwanda',
  r_union: 'R Union',
  saudi_arabia: 'Saudi Arabia',
  senegal: 'Senegal',
  serbia: 'Serbia',
  singapore: 'Singapore',
  slovakia: 'Slovakia',
  slovenia: 'Slovenia',
  somalia: 'Somalia',
  south_africa: 'South Africa',
  south_sudan: 'South Sudan',
  spain: 'Spain',
  sri_lanka: 'Sri Lanka',
  sudan: 'Sudan',
  suriname: 'Suriname',
  sweden: 'Sweden',
  switzerland: 'Switzerland',
  syria: 'Syria',
  taiwan: 'Taiwan',
  tajikistan: 'Tajikistan',
  tanzania: 'Tanzania',
  thailand: 'Thailand',
  timor_leste: 'Timor Leste',
  togo: 'Togo',
  tonga: 'Tonga',
  tunisia: 'Tunisia',
  turkey: 'Turkey',
  turkmenistan: 'Turkmenistan',
  uganda: 'Uganda',
  ukraine: 'Ukraine',
  united_arab_emirates: 'United Arab Emirates',
  united_kingdom: 'United Kingdom',
  united_states: 'United States',
  uruguay: 'Uruguay',
  uzbekistan: 'Uzbekistan',
  venezuela: 'Venezuela',
  vietnam: 'Vietnam',
  yemen: 'Yemen',
  zambia: 'Zambia',
  zimbabwe: 'Zimbabwe',
  verify_your_account: 'Verify Your Account',
  check_your_email_address_to_verify_your_account:
    'Check Your Email Address To Verify Your Account',
  complete_verification_by_providing_the_code_that_you_received_by_email:
    'Complete Verification By Providing The Code That You Received By Email',
  verify_now: 'Verify Now',
  dashboard: 'Dashboard',
  customer: 'Customer',
  people: 'People',
  company: 'Company',
  lead: 'Lead',
  offer: 'Offer',
  invoice: 'Invoice',
  quote: 'Quote',
  payment: 'Payment',
  product: 'Product',
  product_category: 'Product Category',
  expense: 'Expense',
  expenses_category: 'Expenses Category',
  settings: 'Settings',
  admin: 'Admin',
  currency: 'Currency',
  payment_mode: 'Payment Mode',
  taxes: 'Taxes',
  about: 'About',
  profile_settings: 'Profile Settings',
  app_settings: 'App Settings',
  logout: 'Logout',
  number: 'Number',
  client: 'Client',
  total: 'Total',
  status: 'Status',
  invoices_preview: 'Invoices Preview',
  quotes_preview: 'Quotes Preview',
  offers_preview: 'Offers Preview',
  payments_preview: 'Payments Preview',
  this_month: 'This Month',
  unpaid: 'Unpaid',
  not_paid: 'Not Paid',
  recent_invoices: 'Recent Invoices',
  recent_quotes: 'Recent Quotes',
  customer_preview: 'Customer Preview',
  show: 'Show',
  edit: 'Edit',
  download: 'Download',
  draft: 'Draft',
  pending: 'Pending',
  sent: 'Sent',
  declined: 'Declined',
  accepted: 'Accepted',
  expired: 'Expired',
  new_customer_this_month: 'New Customer This Month',
  active_customer: 'Active Customer',
  overdue: 'Overdue',
  partially: 'Partially',
  paid: 'Paid',
  sign_in: 'Sign In',
  log_in: 'Log In',
  register_now: 'Register Now',
  remember_me: 'Remember Me',
  forgot_password: 'Forgot Password',
  forget_password: 'Forget Password',
  request_new_password: 'Request New Password',
  password_reset_in_progress: 'Password Reset In Progress',
  check_your_email_address_to_reset_your_password:
    'Check Your Email Address To Reset Your Password',
  login: 'Login',
  reset_password: 'Reset Password',
  update_password: 'Update Password',
  profile: 'Profile',
  first_name: 'First Name',
  last_name: 'Last Name',
  role: 'Role',
  close: 'Close',
  save: 'Save',
  photo: 'Photo',
  click_to_upload: 'Click To Upload',
  new_password: 'New Password',
  confirm_password: 'Confirm Password',
  general_settings: 'General Settings',
  company_settings: 'Company Settings',
  company_logo: 'Company Logo',
  currency_settings: 'Currency Settings',
  finance_settings: 'Finance Settings',
  settings_list: 'Settings List',
  add_new_settings: 'Add New Settings',
  update_your_app_configuration: 'Update Your App Configuration',
  language: 'Language',
  date_format: 'Date Format',
  update_your_company_informations: 'Update Your Company Informations',
  company_name: 'Company Name',
  company_address: 'Company Address',
  company_state: 'Company State',
  company_country: 'Company Country',
  company_email: 'Company Email',
  company_phone: 'Company Phone',
  company_cell: 'Company Cell',
  company_website: 'Company Website',
  company_tax_number: 'Company Tax Number',
  company_vat_number: 'Company Vat Number',
  company_reg_number: 'Company Reg Number',
  update_company_logo: 'Update Company Logo',
  money_format_settings: 'Money Format Settings',
  default_currency: 'Default Currency',
  select_default_currency: 'Select Default Currency',
  update_company_finance_settings: 'Update Company Finance Settings',
  last_invoice_number: 'Last Invoice Number',
  last_quote_number: 'Last Quote Number',
  last_offer_number: 'Last Offer Number',
  last_payment_number: 'Last Payment Number',
  client_list: 'Client List',
  add_new_client: 'Add New Client',
  delete: 'Delete',
  type: 'Type',
  phone: 'Phone',
  refresh: 'Refresh',
  are_you_sure_you_want_to_delete: 'Are You Sure You Want To Delete',
  delete_confirmation: 'Delete Confirmation',
  remove: 'Remove',
  cancel: 'Cancel',
  select_date: 'Select Date',
  add_new_person: 'Add New Person',
  add_new_company: 'Add New Company',
  submit: 'Submit',
  person: 'Person',
  people_list: 'People List',
  firstname: 'Firstname',
  lastname: 'Lastname',
  company_list: 'Company List',
  contact: 'Contact',
  website: 'Website',
  lead_list: 'Lead List',
  add_new_lead: 'Add New Lead',
  source: 'Source',
  notes: 'Notes',
  new: 'New',
  in_negociation: 'In Negociation',
  won: 'Won',
  loose: 'Loose',
  canceled: 'Canceled',
  assigned: 'Assigned',
  on_hold: 'On Hold',
  waiting: 'Waiting',
  linkedin: 'Linkedin',
  social_media: 'Social Media',
  advertising: 'Advertising',
  friend: 'Friend',
  professionals_network: 'Professionals Network',
  customer_referral: 'Customer Referral',
  sales: 'Sales',
  other: 'Other',
  add_new: 'Add New',
  date: 'Date',
  sub_total: 'Sub Total',
  note: 'Note',
  offer_list: 'Offer List',
  add_new_offer: 'Add New Offer',
  year: 'Year',
  expire_date: 'Expire Date',
  item: 'Item',
  description: 'Description',
  quantity: 'Quantity',
  price: 'Price',
  add_new_tax: 'Add New Tax',
  select_tax_value: 'Select Tax Value',
  add_field: 'Add Field',
  error_404: 'Error 404',
  sorry_the_page_you_requested_does_not_exist: 'Sorry The Page You Requested Does Not Exist',
  back: 'Back',
  download_pdf: 'Download Pdf',
  send_by_email: 'Send By Email',
  convert_to_invoice: 'Convert To Invoice',
  subtotal: 'Subtotal',
  address: 'Address',
  update: 'Update',
  expired_date: 'Expired Date',
  created_by: 'Created By',
  invoice_list: 'Invoice List',
  add_new_invoice: 'Add New Invoice',
  record_payment: 'Record Payment',
  tax_total: 'Tax Total',
  show_invoice: 'Show Invoice',
  payment_status: 'Payment Status',
  discount: 'Discount',
  amount: 'Amount',
  reference: 'Reference',
  add_payment_mode: 'Add Payment Mode',
  quote_list: 'Quote List',
  add_new_quote: 'Add New Quote',
  payment_list: 'Payment List',
  add_new_payment: 'Add New Payment',
  payment_information: 'Payment Information',
  total_paid: 'Total Paid',
  total_remaining: 'Total Remaining',
  product_list: 'Product List',
  add_new_product: 'Add New Product',
  ref: 'Ref',
  product_category_list: 'Product Category List',
  add_new_product_category: 'Add New Product Category',
  color: 'Color',
  enabled: 'Enabled',
  expense_list: 'Expense List',
  add_new_expense: 'Add New Expense',
  expense_category: 'Expense Category',
  expense_category_list: 'Expense Category List',
  add_new_expense_category: 'Add New Expense Category',
  admin_list: 'Admin List',
  add_new_admin: 'Add New Admin',
  admin_super_admin: 'Admin Super Admin',
  staff_admin_crud: 'Staff Admin Crud',
  staff_cru: 'Staff Cru',
  create_and_read_only: 'Create And Read Only',
  read_only: 'Read Only',
  currency_list: 'Currency List',
  add_new_currency: 'Add New Currency',
  currency_name: 'Currency Name',
  currency_code: 'Currency Code',
  currency_symbol: 'Currency Symbol',
  currency_position: 'Currency Position',
  decimal_separator: 'Decimal Separator',
  thousand_separator: 'Thousand Separator',
  cent_precision: 'Cent Precision',
  zero_format: 'Zero Format',
  default: 'Default',
  payment_mode_list: 'Payment Mode List',
  add_new_payment_mode: 'Add New Payment Mode',
  default_mode: 'Default Mode',
  value: 'Value',
  taxes_list: 'Taxes List',
  do_you_need_help_on_customize_of_this_app: 'Do You Need Help On Customize Of This App',
  contact_us: 'Contact Us',
  customers: 'Customers',
  peoples: 'Peoples',
  companies: 'Companies',
  leads: 'Leads',
  offer_leads: 'Offer Leads',
  invoices: 'Invoices',
  quotes: 'Quotes',
  payments: 'Payments',
  products: 'Products',
  products_category: 'Products Category',
  expenses: 'Expenses',
  currencies: 'Currencies',
  payments_mode: 'Payments Mode',
  account_owner: 'Account Owner',
  create_only: 'Create Only',
  enter_code: 'Enter Code',
  offers: 'Offers',
  proforma_invoices: 'quote',
};


================================================
FILE: backend/src/locale/useLanguage.js
================================================
const { readBySettingKey } = require('@/middlewares/settings');

const getLabel = (lang, key) => {
  try {
    const lowerCaseKey = key
      .toLowerCase()
      .replace(/[^a-zA-Z0-9]/g, '_')
      .replace(/ /g, '_');

    if (lang[lowerCaseKey]) return lang[lowerCaseKey];
    else {
      const remove_underscore_fromKey = lowerCaseKey.replace(/_/g, ' ').split(' ');

      const conversionOfAllFirstCharacterofEachWord = remove_underscore_fromKey.map(
        (word) => word[0].toUpperCase() + word.substring(1)
      );

      const label = conversionOfAllFirstCharacterofEachWord.join(' ');

      return label;
    }
  } catch (error) {
    return 'No translate Found';
  }
};

const useSelector = () => {
  const defaultfilePath = `./translation/en_us`;

  const langFile = require(defaultfilePath);
  return langFile;
};

const useLanguage = ({ selectedLang }) => {
  const lang = useSelector();
  const translate = (value) => {
    const text = getLabel(lang, value);
    return text;
  };
  return translate;
};

module.exports = useLanguage;


================================================
FILE: backend/src/middlewares/inventory/generateUniqueNumber.js
================================================
function generateUniqueNumber(uniqueId, numberLength = 13) {
  const currentDate = new Date();
  const year = (currentDate.getFullYear() % 100).toString().padStart(2, '0');
  const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
  const day = currentDate.getDate().toString().padStart(2, '0');
  const randomNumber = Math.floor(Math.random() * 900) + 100;
  const number = (uniqueId + 1).toString().padStart(numberLength - 9, '0'); // numberLength - 9 , 9 is length day + month + year + randomNumber
  return day + month + year + randomNumber + number;
}

module.exports = generateUniqueNumber;


================================================
FILE: backend/src/middlewares/inventory/index.js
================================================
const generateUniqueNumber = require('../inventory/generateUniqueNumber');

module.exports = {
  generateUniqueNumber,
};


================================================
FILE: backend/src/middlewares/serverData.js
================================================
const mongoose = require('mongoose');
exports.getData = ({ model }) => {
  const Model = mongoose.model(model);
  const result = Model.find({ removed: false, enabled: true });
  return result;
};

exports.getOne = ({ model, id }) => {
  const Model = mongoose.model(model);
  const result = Model.findOne({ _id: id, removed: false });
  return result;
};


================================================
FILE: backend/src/middlewares/settings/increaseBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const increaseBySettingKey = async ({ settingKey }) => {
  try {
    if (!settingKey) {
      return null;
    }

    const result = await Model.findOneAndUpdate(
      { settingKey },
      {
        $inc: { settingValue: 1 },
      },
      {
        new: true, // return the new result instead of the old one
        runValidators: true,
      }
    ).exec();

    // If no results found, return document not found
    if (!result) {
      return null;
    } else {
      // Return success resposne
      return result;
    }
  } catch {
    return null;
  }
};

module.exports = increaseBySettingKey;


================================================
FILE: backend/src/middlewares/settings/index.js
================================================
const listBySettingKey = require('./listBySettingKey');
const readBySettingKey = require('./readBySettingKey');
const listAllSettings = require('./listAllSettings');
const updateBySettingKey = require('./updateBySettingKey');
const increaseBySettingKey = require('./increaseBySettingKey');
const loadSettings = require('./loadSettings');

module.exports = {
  loadSettings,
  listAllSettings,
  listBySettingKey,
  readBySettingKey,
  updateBySettingKey,
  increaseBySettingKey,
};


================================================
FILE: backend/src/middlewares/settings/listAllSettings.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const listAllSettings = async () => {
  try {
    //  Query the database for a list of all results
    const result = await Model.find({
      removed: false,
    }).exec();

    if (result.length > 0) {
      return result;
    } else {
      return [];
    }
  } catch {
    return [];
  }
};

module.exports = listAllSettings;


================================================
FILE: backend/src/middlewares/settings/listBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const listBySettingKey = async ({ settingKeyArray = [] }) => {
  try {
    // Find document by id

    const settingsToShow = { $or: [] };

    if (settingKeyArray.length === 0) {
      return [];
    }

    for (const settingKey of settingKeyArray) {
      settingsToShow.$or.push({ settingKey });
    }
    let results = await Model.find({ ...settings }).where('removed', false);

    // If no results found, return document not found
    if (results.length >= 1) {
      return results;
    } else {
      return [];
    }
  } catch {
    return [];
  }
};

module.exports = listBySettingKey;


================================================
FILE: backend/src/middlewares/settings/loadSettings.js
================================================
const listAllSettings = require('./listAllSettings');

const loadSettings = async () => {
  const allSettings = {};
  const datas = await listAllSettings();
  datas.forEach(({ settingKey, settingValue }) => {
    allSettings[settingKey] = settingValue;
  });
  return allSettings;
};

module.exports = loadSettings;


================================================
FILE: backend/src/middlewares/settings/readBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const readBySettingKey = async ({ settingKey }) => {
  try {
    // Find document by id

    if (!settingKey) {
      return null;
    }

    const result = await Model.findOne({ settingKey });
    // If no results found, return document not found
    if (!result) {
      return null;
    } else {
      // Return success resposne
      return result;
    }
  } catch {
    return null;
  }
};

module.exports = readBySettingKey;


================================================
FILE: backend/src/middlewares/settings/updateBySettingKey.js
================================================
const mongoose = require('mongoose');

const Model = mongoose.model('Setting');

const updateBySettingKey = async ({ settingKey, settingValue }) => {
  try {
    if (!settingKey || !settingValue) {
      return null;
    }

    const result = await Model.findOneAndUpdate(
      { settingKey },
      {
        settingValue,
      },
      {
        new: true, // return the new result instead of the old one
        runValidators: true,
      }
    ).exec();
    // If no results found, return document not found
    if (!result) {
      return null;
    } else {
      // Return success resposne
      return result;
    }
  } catch {
    return null;
  }
};

module.exports = updateBySettingKey;


================================================
FILE: backend/src/middlewares/uploadMiddleware/DoSingleStorage.js
================================================
require('dotenv').config({ path: '.env' });
require('dotenv').config({ path: '.env.local' });

const path = require('path');
const { slugify } = require('transliteration');
const fileFilterMiddleware = require('./utils/fileFilterMiddleware');

const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');

const secretAccessKey = process.env.DO_SPACES_SECRET;
const accessKeyId = process.env.DO_SPACES_KEY;
const endpoint = 'https://' + process.env.DO_SPACES_URL;
const region = process.env.REGION;

const clientParams = {
  endpoint: endpoint,
  region: region,
  credentials: {
    accessKeyId,
    secretAccessKey,
  },
};

const DoSingleStorage = ({
  entity,
  fileType = 'default',
  uploadFieldName = 'file',
  fieldName = 'file',
}) => {
  return async function (req, res, next) {
    if (!req.files || Object.keys(req.files)?.length === 0 || !req.files?.file) {
      req.body[fieldName] = null;
      next();
    } else {
      const s3Client = new S3Client(clientParams);

      try {
        if (!fileFilterMiddleware({ type: fileType, mimetype: req.files.file.mimetype })) {
          // skip upload if File type not supported
          throw new Error('Uploaded file type not supported');
          // next();
        }
        let fileExtension = path.extname(req.files.file.name);
        const fileNameWithoutExt = path.parse(req.files.file.name).name;

        let uniqueFileID = Math.random().toString(36).slice(2, 7); // generates unique ID of length 5

        let originalname = '';
        if (req.body.seotitle) {
          originalname = slugify(req.body.seotitle.toLocaleLowerCase()); // convert any language to English characters
        } else {
          originalname = slugify(fileNameWithoutExt.toLocaleLowerCase()); // convert any language to English characters
        }

        let _fileName = `${originalname}-${uniqueFileID}${fileExtension}`;

        const filePath = `public/uploads/${entity}/${_fileName}`;

        let uploadParams = {
          Key: `${filePath}`,
          Bucket: process.env.DO_SPACES_NAME,
          ACL: 'public-read',
          Body: req.files.file.data,
        };
        const command = new PutObjectCommand(uploadParams);
        const s3response = await s3Client.send(command);

        if (s3response.$metadata.httpStatusCode === 200) {
          // saving file name and extension in request upload object
          req.upload = {
            fileName: _fileName,
            fieldExt: fileExtension,
            entity: entity,
            fieldName: fieldName,
            fileType: fileType,
            filePath: filePath,
          };

          req.body[fieldName] = filePath;
          next();
        }
      } catch (error) {
        return res.status(403).json({
          success: false,
          result: null,
          controller: 'DoSingleStorage.js',
          message: 'Error on uploading file',
        });
      }
    }
  };
};

module.exports = DoSingleStorage;


================================================
FILE: backend/src/middlewares/uploadMiddleware/LocalSingleStorage.js
================================================
const multer = require('multer');
const path = require('path');
const { slugify } = require('transliteration');

const fileFilter = require('./utils/LocalfileFilter');

const singleStorageUpload = ({
  entity,
  fileType = 'default',
  uploadFieldName = 'file',
  fieldName = 'file',
}) => {
  var diskStorage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, `src/public/uploads/${entity}`);
    },
    filename: function (req, file, cb) {
      try {
        // fetching the file extension of the uploaded file
        let fileExtension = path.extname(file.originalname);
        let uniqueFileID = Math.random().toString(36).slice(2, 7); // generates unique ID of length 5

        let originalname = '';
        if (req.body.seotitle) {
          originalname = slugify(req.body.seotitle.toLocaleLowerCase()); // convert any language to English characters
        } else {
          originalname = slugify(file.originalname.split('.')[0].toLocaleLowerCase()); // convert any language to English characters
        }

        let _fileName = `${originalname}-${uniqueFileID}${fileExtension}`;

        const filePath = `public/uploads/${entity}/${_fileName}`;
        // saving file name and extension in request upload object
        req.upload = {
          fileName: _fileName,
          fieldExt: fileExtension,
          entity: entity,
          fieldName: fieldName,
          fileType: fileType,
          filePath: filePath,
        };

        req.body[fieldName] = filePath;

        cb(null, _fileName);
      } catch (error) {
        cb(error); // pass the error to the callback
      }
    },
  });

  let filterType = fileFilter(fileType);

  const multerStorage = multer({ storage: diskStorage, fileFilter: filterType }).single('file');
  return multerStorage;
};

module.exports = singleStorageUpload;


================================================
FILE: backend/src/middlewares/uploadMiddleware/index.js
================================================
const singleStorageUpload = require('./singleStorageUpload');
const LocalSingleStorage = require('./LocalSingleStorage');

module.exports = {
  singleStorageUpload,
  LocalSingleStorage,
};


================================================
FILE: backend/src/middlewares/uploadMiddleware/singleStorageUpload.js
================================================
const multer = require('multer');
const path = require('path');
const { slugify } = require('transliteration');

const fileFilter = require('./utils/LocalfileFilter');

const singleStorageUpload = ({
  entity,
  fileType = 'default',
  uploadFieldName = 'file',
  fieldName = 'file',
}) => {
  var diskStorage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, `src/public/uploads/${entity}`);
    },
    filename: function (req, file, cb) {
      try {
        // fetching the file extension of the uploaded file
        let fileExtension = path.extname(file.originalname);
        let uniqueFileID = Math.random().toString(36).slice(2, 7); // generates unique ID of length 5

        let originalname = '';
        if (req.body.seotitle) {
          originalname = slugify(req.body.seotitle.toLocaleLowerCase()); // convert any language to English characters
        } else {
          originalname = slugify(file.originalname.split('.')[0].toLocaleLowerCase()); // convert any language to English characters
        }

        let _fileName = `${originalname}-${uniqueFileID}${fileExtension}`;

        const filePath = `public/uploads/${entity}/${_fileName}`;
        // saving file name and extension in request upload object
        req.upload = {
          fileName: _fileName,
          fieldExt: fileExtension,
          entity: entity,
          fieldName: fieldName,
          fileType: fileType,
          filePath: filePath,
        };

        req.body[fieldName] = filePath;

        cb(null, _fileName);
      } catch (error) {
        cb(error); // pass the error to the callback
      }
    },
  });

  let filterType = fileFilter(fileType);

  const multerStorage = multer({ storage: diskStorage, fileFilter: filterType }).single('file');
  return multerStorage;
};

module.exports = singleStorageUpload;


================================================
FILE: backend/src/middlewares/uploadMiddleware/utils/LocalfileFilter.js
================================================
const fileFilter =
  (type = 'default') =>
  (req, file, cb) => {
    // array containing all the possible file types
    const _fileType = [
      'image/jpeg',
      'image/png',
      'image/gif',
      'image/webp',
      'image/svg+xml',
      'application/msword',
      'text/plain',
      'text/csv',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'application/vnd.ms-excel',
      'application/pdf',
      'application/zip',
      'application/vnd.rar',
      'video/mp4',
      'video/x-msvideo',
      'audio/mpeg',
      'video/webm',
    ];

    if (type === 'default') {
      return cb(null, true);
    } else {
      let _flag = _fileType.includes(file.mimetype);

      if (type === 'image') {
        if (!file.mimetype.startsWith('image/')) {
          _flag = false;
        }
      } else if (type === 'pdf') {
        if (!file.mimetype.startsWith('application/pdf')) {
          _flag = false;
        }
      } else if (type === 'video') {
        if (!file.mimetype.startsWith('video/')) {
          _flag = false;
        }
      } else if (type === 'audio') {
        if (!file.mimetype.startsWith('audio/')) {
          _flag = false;
        }
      } else if (type === 'text') {
        if (
          !file.mimetype.startsWith('text/') &&
          !file.mimetype.startsWith('application/vnd.ms-excel') &&
          !file.mimetype.startsWith('application/msword') &&
          !file.mimetype.startsWith(
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
          )
        ) {
          _flag = false;
        }
      } else if (type === 'excel') {
        if (
          !file.mimetype.startsWith('application/vnd.ms-excel') &&
          !file.mimetype.startsWith(
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
          )
        ) {
          _flag = false;
        }
      } else if (type === 'compressed') {
        if (
          !file.mimetype.startsWith('application/zip') &&
          !file.mimetype.startsWith('application/x-zip-compressed') &&
          !file.mimetype.startsWith('application/vnd.rar')
        ) {
          _flag = false;
        }
      }

      if (_flag) {
        return cb(null, true);
      } else {
        return cb(new Error(`${file.mimetype} File type not supported!`));
      }
    }
  };

module.exports = fileFilter;


================================================
FILE: backend/src/middlewares/uploadMiddleware/utils/fileFilterMiddleware.js
================================================
const fileFilterMiddleware = ({ type = 'default', mimetype }) => {
  // array containing all the possible file types
  const _fileType = [
    'image/jpeg',
    'image/png',
    'image/gif',
    'image/webp',
    'image/svg+xml',
    'application/msword',
    'text/plain',
    'text/csv',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-excel',
    'application/pdf',
    'application/zip',
    'application/vnd.rar',
    'video/mp4',
    'video/x-msvideo',
    'audio/mpeg',
    'video/webm',
  ];

  if (type === 'default') {
    return true;
  } else {
    let _flag = _fileType.includes(mimetype);

    if (type === 'image') {
      if (!mimetype.startsWith('image/')) {
        _flag = false;
      }
    } else if (type === 'pdf') {
      if (!mimetype.startsWith('application/pdf')) {
        _flag = false;
      }
    } else if (type === 'video') {
      if (!mimetype.startsWith('video/')) {
        _flag = false;
      }
    } else if (type === 'audio') {
      if (!mimetype.startsWith('audio/')) {
        _flag = false;
      }
    } else if (type === 'text') {
      if (
        !mimetype.startsWith('text/') &&
        !mimetype.startsWith('application/vnd.ms-excel') &&
        !mimetype.startsWith('application/msword') &&
        !mimetype.startsWith(
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        )
      ) {
        _flag = false;
      }
    } else if (type === 'excel') {
      if (
        !mimetype.startsWith('application/vnd.ms-excel') &&
        !mimetype.startsWith('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
      ) {
        _flag = false;
      }
    } else if (type === 'compressed') {
      if (
        !mimetype.startsWith('application/zip') &&
        !mimetype.startsWith('application/x-zip-compressed') &&
        !mimetype.startsWith('application/vnd.rar')
      ) {
        _flag = false;
      }
    }

    if (_flag) {
      return true;
    } else {
      return false;
    }
  }
};

module.exports = fileFilterMiddleware;


================================================
FILE: backend/src/models/.gitkeep
================================================


================================================
FILE: backend/src/models/appModels/Client.js
================================================
const mongoose = require('mongoose');

const schema = new mongoose.Schema({
  removed: {
    type: Boolean,
    default: false,
  },
  enabled: {
    type: Boolean,
    default: true,
  },

  name: {
    type: String,
    required: true,
  },
  phone: String,
  country: String,
  address: String,
  email: String,
  createdBy: { type: mongoose.Schema.ObjectId, ref: 'Admin' },
  assigned: { type: mongoose.Schema.ObjectId, ref: 'Admin' },
  created: {
    type: Date,
    default: Date.now,
  },
  updated: {
    type: Date,
    default: Date.now,
  },
});

schema.plugin(require('mongoose-autopopulate'));

module.exports = mongoose.model('Client', schema);


================================================
FILE: backend/src/models/appModels/Invoice.js
================================================
const mongoose = require('mongoose');

const invoiceSchema = new mongoose.Schema({
  removed: {
    type: Boolean,
    default: false,
  },

  createdBy: { type: mongoose.Schema.ObjectId, ref: 'Admin', required: true },
  number: {
    type: Number,
    required: true,
  },
  year: {
    type: Number,
    required: true,
  },
  content: String,
  recurring: {
    type: String,
    enum: ['daily', 'weekly', 'monthly', 'annually', 'quarter'],
  },
  date: {
    type: Date,
    required: true,
  },
  expiredDate: {
    type: Date,
    required: true,
  },
  client: {
    type: mongoose.Schema.ObjectId,
    ref: 'Client',
    required: true,
    autopopulate: true,
  },
  converted: {
    from: {
      type: String,
      enum: ['quote', 'offer'],
    },
    offer: {
      type: mongoose.Schema.ObjectId,
      ref: 'Offer',
    },
    quote: {
      type: mongoose.Schema.ObjectId,
      ref: 'Quote',
    },
  },
  items: [
    {
      // product: {
      //   type: mongoose.Schema.ObjectId,
      //   ref: 'Product',
      //   // required: true,
      // },
      itemName: {
        type: String,
        required: true,
      },
      description: {
        type: String,
      },
      quantity: {
        type: Number,
        default: 1,
        required: true,
      },
      price: {
        type: Number,
        required: true,
      },
      // discount: {
      //   type: Number,
      //   default: 0,
      // },
      // taxRate: {
      //   type: Number,
      //   default: 0,
      // },
      // subTotal: {
      //   type: Number,
      //   default: 0,
      // },
      // taxTotal: {
      //   type: Number,
      //   default: 0,
      // },
      total: {
        type: Number,
        required: true,
      },
    },
  ],
  taxRate: {
    type: Number,
    default: 0,
  },
  subTotal: {
    type: Number,
    default: 0,
  },
  taxTotal: {
    type: Number,
    default: 0,
  },
  total: {
    type: Number,
    default: 0,
  },
  currency: {
    type: String,
    default: 'NA',
    uppercase: true,
    required: true,
  },
  credit: {
    type: Number,
    default: 0,
  },
  discount: {
    type: Number,
    default: 0,
  },
  payment: [
    {
      type: mongoose.Schema.ObjectId,
      ref: 'Payment',
    },
  ],
  paymentStatus: {
    type: String,
    default: 'unpaid',
    enum: ['unpaid', 'paid', 'partially'],
  },
  isOverdue: {
    type: Boolean,
    default: false,
  },
  approved: {
    type: Boolean,
    default: false,
  },
  notes: {
    type: String,
  },
  status: {
    type: String,
    enum: ['draft', 'pending', 'sent', 'refunded', 'cancelled', 'on hold'],
    default: 'draft',
  },
  pdf: {
    type: String,
  },
  files: [
    {
      id: String,
      name: String,
      path: String,
      description: String,
      isPublic: {
        type: Boolean,
        default: true,
      },
    },
  ],
  updated: {
    type: Date,
    default: Date.now,
  },
  created: {
    type: Date,
    default: Date.now,
  },
});

invoiceSchema.plugin(require('mongoose-autopopulate'));
module.exports = mongoose.model('Invoice', invoiceSchema);


================================================
FILE: backend/src/models/appModels/Payment.js
================================================
const mongoose = require('mongoose');

const paymentSchema = new mongoose.Schema({
  removed: {
    type: Boolean,
    default: false,
  },

  createdBy: { type: mongoose.Schema.ObjectId, ref: 'Admin', autopopulate: true, required: true },
  number: {
    type: Number,
    required: true,
  },
  client: {
    type: mongoose.Schema.ObjectId,
    ref: 'Client',
    autopopulate: true,
    required: true,
  },
  invoice: {
    type: mongoose.Schema.ObjectId,
    ref: 'Invoice',
    required: true,
    autopopulate: true,
  },
  date: {
    type: Date,
    default: Date.now,
    required: true,
  },
  amount: {
    type: Number,
    required: true,
  },
  currency: {
    type: String,
    default: 'NA',
    uppercase: true,
    required: true,
  },
  ref: {
    type: String,
  },
  description: {
    type: String,
  },
  updated: {
    type: Date,
    default: Date.now,
  },
  created: {
    type: Date,
    default: Date.now,
  },
});
paymentSchema.plugin(require('mongoose-autopopulate'));
module.exports = mongoose.model('Payment', paymentSchema);


================================================
FILE: backend/src/models/coreModels/Admin.js
================================================
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const adminSchema = new Schema({
  removed: {
    type: Boolean,
    default: false,
  },
  enabled: {
    type: Boolean,
    default: false,
  },

  email: {
    type: String,
    lowercase: true,
    trim: true,
    required: true,
  },
  name: { type: String, required: true },
  surname: { type: String },
  photo: {
    type: String,
    trim: true,
  },
  created: {
    type: Date,
    default: Date.now,
  },
  role: {
    type: String,
    default: 'owner',
    enum: ['owner'],
  },
});

module.exports = mongoose.model('Admin', adminSchema);


================================================
FILE: backend/src/models/coreModels/AdminPassword.js
================================================
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const bcrypt = require('bcryptjs');

const AdminPasswordSchema = new Schema({
  removed: {
    type: Boolean,
    default: false,
  },
  user: { type: mongoose.Schema.ObjectId, ref: 'Admin', required: true, unique: true },
  password: {
    type: String,
    required: true,
  },
  salt: {
    type: String,
    required: true,
  },
  emailToken: String,
  resetToken: String,
  emailVerified: {
    type: Boolean,
    default: false,
  },
  authType: {
    type: String,
    default: 'email',
  },
  loggedSessions: {
    type: [String],
    default: [],
  },
});

// AdminPasswordSchema.index({ user: 1 });
// generating a hash
AdminPasswordSchema.methods.generateHash = function (salt, password) {
  return bcrypt.hashSync(salt + password);
};

// checking if password is valid
AdminPasswordSchema.methods.validPassword = function (salt, userpassword) {
  return bcrypt.compareSync(salt + userpassword, this.password);
};

module.exports = mongoose.model('AdminPassword', AdminPasswordSchema);


================================================
FILE: backend/src/models/coreModels/Setting.js
================================================
const mongoose = require('mongoose');

const settingSchema = new mongoose.Schema({
  removed: {
    type: Boolean,
    default: false,
  },
  enabled: {
    type: Boolean,
    default: true,
  },

  settingCategory: {
    type: String,
    required: true,
    lowercase: true,
  },
  settingKey: {
    type: String,
    lowercase: true,
    required: true,
  },
  settingValue: {
    type: mongoose.Schema.Types.Mixed,
  },
  valueType: {
    type: String,
    default: 'String',
  },
  isPrivate: {
    type: Boolean,
    default: false,
  },
  isCoreSetting: {
    type: Boolean,
    default: false,
  },
});

module.exports = mongoose.model('Setting', settingSchema);


================================================
FILE: backend/src/models/coreModels/Upload.js
================================================
const mongoose = require('mongoose');

const uploadSchema = new mongoose.Schema({
  removed: {
    type: Boolean,
    default: false,
  },
  enabled: {
    type: Boolean,
    default: true,
  },

  modelName: {
    type: String,
    trim: true,
  },
  fieldId: {
    type: String,
    required: true,
  },
  fileName: {
    type: String,
    required: true,
  },
  fileType: {
    type: String,
    enum: [
      'jpeg',
      'jpg',
      'png',
      'gif',
      'webp',
      'doc',
      'txt',
      'csv',
      'docx',
      'xls',
      'xlsx',
      'pdf',
      'zip',
      'rar',
      'mp4',
      'mov',
      'avi',
      'mp3',
      'm4a',
      'webm',
    ],
    required: true,
  },
  isPublic: {
    type: Boolean,
    required: true,
  },
  userID: {
    type: mongoose.SchemaTypes.ObjectId,
    required: true,
  },
  isSecure: {
    type: Boolean,
    required: true,
  },
  path: {
    type: String,
    required: true,
  },
  created: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model('Upload ', uploadSchema);


================================================
FILE: backend/src/models/utils/index.js
================================================
const { basename, extname } = require('path');
const { globSync } = require('glob');

const appModelsFiles = globSync('./src/models/appModels/**/*.js');

const pattern = './src/models/**/*.js';

const modelsFiles = globSync(pattern).map((filePath) => {
  const fileNameWithExtension = basename(filePath);
  const fileNameWithoutExtension = fileNameWithExtension.replace(
    extname(fileNameWithExtension),
    ''
  );
  return fileNameWithoutExtension;
});

const constrollersList = [];
const appModelsList = [];
const entityList = [];
const routesList = [];

for (const filePath of appModelsFiles) {
  const fileNameWithExtension = basename(filePath);
  const fileNameWithoutExtension = fileNameWithExtension.replace(
    extname(fileNameWithExtension),
    ''
  );
  const firstChar = fileNameWithoutExtension.charAt(0);
  const modelName = fileNameWithoutExtension.replace(firstChar, firstChar.toUpperCase());
  const fileNameLowerCaseFirstChar = fileNameWithoutExtension.replace(
    firstChar,
    firstChar.toLowerCase()
  );
  const entity = fileNameWithoutExtension.toLowerCase();

  controllerName = fileNameLowerCaseFirstChar + 'Controller';
  constrollersList.push(controllerName);
  appModelsList.push(modelName);
  entityList.push(entity);

  const route = {
    entity: entity,
    modelName: modelName,
    controllerName: controllerName,
  };
  routesList.push(route);
}

module.exports = { constrollersList, appModelsList, modelsFiles, entityList, routesList };


================================================
FILE: backend/src/pdf/Invoice.pug
================================================
doctype html
html
  head
    link(rel="shortcut icon" type="image/png" href="/images/icons/favicon.png")
    meta(name="viewport" content="width=device-width, initial-scale=1")
    style.
      .sheet {
        margin: 0;
        width: 100%; 
        height: 297mm;
      }

      body{
        width: 100%; 
        margin: 0;
        padding: 0px ;
        background: #ffffff;
        font-family: sans-serif;
        font-size:12px;
        color:#222
      }
      *, *:before, *:after {
        box-sizing: inherit;
        color:#222
      }

      .clearfix {
        display: block; }
      //- .invoice-container {
      //-   position: relative;
      //-   margin: 0 auto;
      //-   color: #001028;
      //-   background: #fff;
      //-   font-size: 10px;
      //- }
      .left{
        float:left;
      }
      .right{
        float:right;
      }
      .top-area {    
        display: block;
        width:100%;
        
      }
      alignRight :{
        text-align: right !important;
      }
      alignLeft :{
        text-align: left;
      }
      .logo {
        width: 150px;
      }
      .company-info{
        text-align: right;
        font-size:12px;
      }
      h1.invoice{
        font-size:32px;
        color:#52008c;
        margin-top:0;
      }
      p.strong{
        font-weight:700;
      }
      .billTo p {
        text-align: right !important;
        float:right;
        display:block;
        font-size:12px;
        width:100%;
        margin-top:0;
        margin-bottom:10px;
        
      }

      .tableHeader{
        color:#52008c;
      }
      .clearfix {
        display: block; }
      .col {
        float:left;
      }
      .col-1 {
        width: 4.16667%; }

      .col-2 {
        width: 8.33333%; }

      .col-3 {
        width: 12.5%; }

      .col-4 {
        width: 16.66667%; }

      .col-5 {
        width: 20.83333%; }

      .col-6 {
        width: 25%; }

      .col-7 {
        width: 29.16667%; }

      .col-8 {
        width: 33.33333%; }

      .col-9 {
        width: 37.5%; }

      .col-10 {
        width: 41.66667%; }

      .col-11 {
        width: 45.83333%; }

      .col-12 {
        width: 50%; }

      .col-13 {
        width: 54.16667%; }

      .col-14 {
        width: 58.33333%; }

      .col-15 {
        width: 62.5%; }

      .col-16 {
        width: 66.66667%; }

      .col-17 {
        width: 70.83333%; }

      .col-18 {
        width: 75%; }

      .col-19 {
        width: 79.16667%; }

      .col-20 {
        width: 83.33333%; }

      .col-21 {
        width: 87.5%; }

      .col-22 {
        width: 91.66667%; }

      .col-23 {
        width: 95.83333%; }

      .col-24 {
        width: 100%; }
      .space {
        margin-top: 30px;
        margin-bottom: 40px;
        width:100%;
      }
      .top-area .number-invoice > h1 {
        font-weight: 500;
      }
      .about-invoice {
        padding: 0px 15px;
        margin-top: 10px;
        font-size: 13px;
      }
Download .txt
gitextract_uk7xy8q9/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── custom.md
│   │   └── feature_request.md
│   ├── pull_request_template.md
│   └── workflows/
│       ├── CODEOWNERS
│       ├── codesee-arch-diagram.yml
│       └── github-repo-stats.yml
├── CODE-OF-CONDUCT.md
├── CONTRIBUTING.md
├── INSTALLATION-INSTRUCTIONS.md
├── LICENSE
├── README.md
├── SECURITY.md
├── backend/
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .prettierignore
│   ├── .prettierrc
│   ├── .vscode/
│   │   └── settings.json
│   ├── jsconfig.json
│   ├── package.json
│   └── src/
│       ├── app.js
│       ├── controllers/
│       │   ├── appControllers/
│       │   │   ├── clientController/
│       │   │   │   ├── index.js
│       │   │   │   └── summary.js
│       │   │   ├── index.js
│       │   │   ├── invoiceController/
│       │   │   │   ├── create.js
│       │   │   │   ├── index.js
│       │   │   │   ├── paginatedList.js
│       │   │   │   ├── read.js
│       │   │   │   ├── remove.js
│       │   │   │   ├── schemaValidate.js
│       │   │   │   ├── sendMail.js
│       │   │   │   ├── summary.js
│       │   │   │   └── update.js
│       │   │   └── paymentController/
│       │   │       ├── create.js
│       │   │       ├── index.js
│       │   │       ├── remove.js
│       │   │       ├── sendMail.js
│       │   │       ├── summary.js
│       │   │       └── update.js
│       │   ├── coreControllers/
│       │   │   ├── adminAuth/
│       │   │   │   └── index.js
│       │   │   ├── adminController/
│       │   │   │   └── index.js
│       │   │   ├── settingController/
│       │   │   │   ├── index.js
│       │   │   │   ├── listAll.js
│       │   │   │   ├── listBySettingKey.js
│       │   │   │   ├── readBySettingKey.js
│       │   │   │   ├── updateBySettingKey.js
│       │   │   │   └── updateManySetting.js
│       │   │   └── setup.js
│       │   ├── middlewaresControllers/
│       │   │   ├── createAuthMiddleware/
│       │   │   │   ├── authUser.js
│       │   │   │   ├── checkAndCorrectURL.js
│       │   │   │   ├── forgetPassword.js
│       │   │   │   ├── index.js
│       │   │   │   ├── isValidAuthToken.js
│       │   │   │   ├── login.js
│       │   │   │   ├── logout.js
│       │   │   │   ├── resetPassword.js
│       │   │   │   └── sendMail.js
│       │   │   ├── createCRUDController/
│       │   │   │   ├── create.js
│       │   │   │   ├── filter.js
│       │   │   │   ├── index.js
│       │   │   │   ├── listAll.js
│       │   │   │   ├── paginatedList.js
│       │   │   │   ├── read.js
│       │   │   │   ├── remove.js
│       │   │   │   ├── search.js
│       │   │   │   ├── summary.js
│       │   │   │   └── update.js
│       │   │   └── createUserController/
│       │   │       ├── index.js
│       │   │       ├── read.js
│       │   │       ├── updatePassword.js
│       │   │       ├── updateProfile.js
│       │   │       └── updateProfilePassword.js
│       │   └── pdfController/
│       │       └── index.js
│       ├── emailTemplate/
│       │   ├── SendEmailTemplate.js
│       │   └── emailVerfication.js
│       ├── handlers/
│       │   ├── downloadHandler/
│       │   │   └── downloadPdf.js
│       │   └── errorHandlers.js
│       ├── helpers.js
│       ├── locale/
│       │   ├── languages.js
│       │   ├── translation/
│       │   │   └── en_us.js
│       │   └── useLanguage.js
│       ├── middlewares/
│       │   ├── inventory/
│       │   │   ├── generateUniqueNumber.js
│       │   │   └── index.js
│       │   ├── serverData.js
│       │   ├── settings/
│       │   │   ├── increaseBySettingKey.js
│       │   │   ├── index.js
│       │   │   ├── listAllSettings.js
│       │   │   ├── listBySettingKey.js
│       │   │   ├── loadSettings.js
│       │   │   ├── readBySettingKey.js
│       │   │   └── updateBySettingKey.js
│       │   └── uploadMiddleware/
│       │       ├── DoSingleStorage.js
│       │       ├── LocalSingleStorage.js
│       │       ├── index.js
│       │       ├── singleStorageUpload.js
│       │       └── utils/
│       │           ├── LocalfileFilter.js
│       │           └── fileFilterMiddleware.js
│       ├── models/
│       │   ├── .gitkeep
│       │   ├── appModels/
│       │   │   ├── Client.js
│       │   │   ├── Invoice.js
│       │   │   └── Payment.js
│       │   ├── coreModels/
│       │   │   ├── Admin.js
│       │   │   ├── AdminPassword.js
│       │   │   ├── Setting.js
│       │   │   └── Upload.js
│       │   └── utils/
│       │       └── index.js
│       ├── pdf/
│       │   ├── Invoice.pug
│       │   ├── Offer.pug
│       │   ├── Payment.pug
│       │   └── Quote.pug
│       ├── routes/
│       │   ├── appRoutes/
│       │   │   └── appApi.js
│       │   └── coreRoutes/
│       │       ├── coreApi.js
│       │       ├── coreAuth.js
│       │       ├── coreDownloadRouter.js
│       │       └── corePublicRouter.js
│       ├── server.js
│       ├── settings/
│       │   ├── index.js
│       │   ├── useAppSettings.js
│       │   ├── useDate.js
│       │   └── useMoney.js
│       ├── setup/
│       │   ├── defaultSettings/
│       │   │   ├── appSettings.json
│       │   │   ├── clientSettings.json
│       │   │   ├── companySettings.json
│       │   │   ├── financeSettings.json
│       │   │   ├── invoiceSettings.json
│       │   │   ├── moneyFormatSettings.json
│       │   │   └── quoteSettings.json
│       │   ├── reset.js
│       │   ├── setup.js
│       │   └── setupConfig.json
│       └── utils/
│           ├── countryList.js
│           ├── currency.js
│           ├── currencyList.js
│           └── is-path-inside.js
├── doc/
│   ├── README.fr.md
│   └── README.sp.md
├── features/
│   ├── ar_eg_ملف_مفتوح_المصدر_مجاني_للبرمجيات_ERP_CRM.md
│   ├── bg_bg_свободен_отворен_източник_erp_crm_софтуер.md
│   ├── bn_bd_ফ্রি_ওপেন_সোর্স_ইআরপি_সিআরএম_সফটওয়্যার.md
│   ├── ca_es_software_erp_crm_de_codi_obert_gratuït.md
│   ├── cs_cz_volný_otevřený_zdroj_erp_crm_software.md
│   ├── da_dk_gratis_åben_kilde_erp_crm_software.md
│   ├── de_de_frei_offene_quelle_erp_crm_software.md
│   ├── el_gr_ελεύθερο_ανοικτο_πηγαίο_erp_crm_λογισμικό.md
│   ├── en_us_free_open_source_erp_crm_software.md
│   ├── es_es_software_erp_crm_de_código_abierto_y_gratis.md
│   ├── et_ee_tasuta_avatud_lähtekoodiga_erp_crm_tarkvara.md
│   ├── fa_ir_رایگان_منبع_باز_نرم‌افزار_مدیریت_مالی_و_ارتباطات.md
│   ├── fi_fi_ilmainen_avoin_lähdekoodi_erp_crm_ohjelmisto.md
│   ├── fr_fr_gratuit_logiciel_erp_crm_open_source.md
│   ├── hi_in_मुफ्त_खुला_स्रोत_ईआरपी_सीआरएम_सॉफ़्टवेयर.md
│   ├── hr_hr_besplatni_otvoreni_izvor_erp_crm_softver.md
│   ├── hu_hu_ingyenes_nyílt_forráskódú_erp_crm_szoftver.md
│   ├── id_id_perangkat_lunak_erp_crm_sumber_terbuka_gratis.md
│   ├── it_it_software_erp_crm_open_source_gratuito.md
│   ├── ja_jp_フリーオープンソースERP CRMソフトウェア.md
│   ├── ko_kr_자유_오픈_소스_ERP_CRM_소프트웨어.md
│   ├── lt_lt_nemokamas_atviras_kodo_erp_crm_programinė_įranga.md
│   ├── lv_lv_bezmaksas_atvērtā_koda_erp_crm_programmatūra.md
│   ├── mk_mk_фрее_опен_сорсе_ерп_црм_софтвер.md
│   ├── ms_my_fail_terbuka_sumber_erp_crm_perisian.md
│   ├── nb_no_gratis_åpen_kilde_erp_crm_programvare.md
│   ├── nl_nl_vrije_open_source_erp_crm_software.md
│   ├── pl_pl_bezpłatne_otwarte_źródło_erp_crm_oprogramowanie.md
│   ├── pt_br_software_de_erp_e_crm_de_código_aberto_gratuito.md
│   ├── pt_pt_software_de_erp_crm_de_código_aberto_gratuito.md
│   ├── ro_ro_software_erp_crm_open_source_gratuit.md
│   ├── ru_ru_бесплатное_открытое_программное_обеспечение_erp_crm.md
│   ├── sk_sk_zdarma_otvorene_zdrojove_erp_crm_software.md
│   ├── sl_si_brezplačni_odprtokodni_erp_crm_programski_oprema.md
│   ├── sr_rs_besplatni_otvoreni_izvor_erp_crm_softver.md
│   ├── sv_se_fri_öppen_källkods_erp_crm_programvara.md
│   ├── th_th_ฟรี_โปรแกรม_ตัวจัดการแหล่งข้อมูลโปรแกรม_ERP_CRM.md
│   ├── tr_tr_ücretsiz_açık_kaynak_erp_crm_yazılımı.md
│   ├── uk_ua_безкоштовне_відкрите_джерело_erp_crm_програмне_забезпечення.md
│   ├── ur_pk_مفت_کھولیں_سورس_erp_crm_سافٹ ویئر.md
│   ├── vi_vn_chương_trình_quản_lý_doanh_nghiệp_crm_nguồn_mở_miễn_phí.md
│   └── zh_cn_免费开源ERP CRM软件.md
└── frontend/
    ├── .eslintrc.js
    ├── .gitignore
    ├── .prettierignore
    ├── .prettierrc
    ├── .vscode/
    │   └── settings.json
    ├── README.md
    ├── index.html
    ├── jsconfig.json
    ├── package.json
    ├── public/
    │   └── robots.txt
    ├── rollup.config.js
    ├── src/
    │   ├── RootApp.jsx
    │   ├── apps/
    │   │   ├── ErpApp.jsx
    │   │   ├── Header/
    │   │   │   ├── HeaderContainer.jsx
    │   │   │   └── UpgradeButton.jsx
    │   │   ├── IdurarOs.jsx
    │   │   └── Navigation/
    │   │       └── NavigationContainer.jsx
    │   ├── auth/
    │   │   ├── auth.service.js
    │   │   └── index.js
    │   ├── components/
    │   │   ├── AutoCompleteAsync/
    │   │   │   └── index.jsx
    │   │   ├── CollapseBox/
    │   │   │   └── index.jsx
    │   │   ├── CreateForm/
    │   │   │   └── index.jsx
    │   │   ├── CrudModal/
    │   │   │   └── index.jsx
    │   │   ├── DataTable/
    │   │   │   └── DataTable.jsx
    │   │   ├── DeleteModal/
    │   │   │   └── index.jsx
    │   │   ├── IconMenu/
    │   │   │   └── index.jsx
    │   │   ├── Loading/
    │   │   │   └── index.jsx
    │   │   ├── MoneyInputFormItem/
    │   │   │   └── index.jsx
    │   │   ├── MultiStepSelectAsync/
    │   │   │   └── index.jsx
    │   │   ├── NotFound/
    │   │   │   └── index.jsx
    │   │   ├── Notification/
    │   │   │   └── index.jsx
    │   │   ├── PageLoader/
    │   │   │   └── index.jsx
    │   │   ├── ReadItem/
    │   │   │   └── index.jsx
    │   │   ├── SearchItem/
    │   │   │   └── index.jsx
    │   │   ├── SelectAsync/
    │   │   │   └── index.jsx
    │   │   ├── SelectTag/
    │   │   │   └── index.jsx
    │   │   ├── SidePanel/
    │   │   │   └── index.jsx
    │   │   ├── TabsContent/
    │   │   │   └── TabsContent.jsx
    │   │   ├── Tag/
    │   │   │   └── index.jsx
    │   │   ├── UpdateForm/
    │   │   │   └── index.jsx
    │   │   ├── Visibility/
    │   │   │   └── index.jsx
    │   │   └── outsideClick.js/
    │   │       ├── demo.js
    │   │       └── index.js
    │   ├── config/
    │   │   └── serverApiConfig.js
    │   ├── context/
    │   │   ├── adavancedCrud/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   ├── selectors.jsx
    │   │   │   └── types.jsx
    │   │   ├── appContext/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   └── types.jsx
    │   │   ├── crud/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   ├── selectors.jsx
    │   │   │   └── types.jsx
    │   │   ├── erp/
    │   │   │   ├── actions.jsx
    │   │   │   ├── index.jsx
    │   │   │   ├── reducer.jsx
    │   │   │   ├── selectors.jsx
    │   │   │   └── types.jsx
    │   │   └── profileContext/
    │   │       ├── actions.jsx
    │   │       ├── index.jsx
    │   │       ├── reducer.jsx
    │   │       ├── selectors.jsx
    │   │       └── types.jsx
    │   ├── forms/
    │   │   ├── AdminForm.jsx
    │   │   ├── AdvancedSettingsForm.jsx
    │   │   ├── CurrencyForm.jsx
    │   │   ├── CustomerForm.jsx
    │   │   ├── DynamicForm/
    │   │   │   └── index.jsx
    │   │   ├── EmployeeForm.jsx
    │   │   ├── ForgetPasswordForm.jsx
    │   │   ├── InventoryForm.jsx
    │   │   ├── LeadForm.jsx
    │   │   ├── LoginForm.jsx
    │   │   ├── OrderForm.jsx
    │   │   ├── PaymentForm.jsx
    │   │   ├── PaymentModeForm.jsx
    │   │   ├── RegisterForm.jsx
    │   │   ├── ResetPasswordForm.jsx
    │   │   ├── TaxForm.jsx
    │   │   └── UpdateEmail.jsx
    │   ├── hooks/
    │   │   ├── useDebounce.jsx
    │   │   ├── useFetch.jsx
    │   │   ├── useMail.jsx
    │   │   ├── useNetwork.jsx
    │   │   ├── useOnFetch.jsx
    │   │   ├── useResponsive.jsx
    │   │   └── useTimeoutFn.jsx
    │   ├── layout/
    │   │   ├── AuthLayout/
    │   │   │   └── index.jsx
    │   │   ├── CrudLayout/
    │   │   │   └── index.jsx
    │   │   ├── DashboardLayout/
    │   │   │   └── index.jsx
    │   │   ├── DefaultLayout/
    │   │   │   └── index.jsx
    │   │   ├── ErpLayout/
    │   │   │   └── index.jsx
    │   │   ├── Footer/
    │   │   │   └── index.jsx
    │   │   ├── ProfileLayout/
    │   │   │   └── index.jsx
    │   │   ├── SettingsLayout/
    │   │   │   └── index.jsx
    │   │   └── index.jsx
    │   ├── locale/
    │   │   ├── Localization.jsx
    │   │   ├── antdLocale.js
    │   │   ├── coreTranslation.js
    │   │   ├── translation/
    │   │   │   ├── en_us.js
    │   │   │   ├── otherTranslation.js
    │   │   │   └── translation.js
    │   │   └── useLanguage.jsx
    │   ├── main.jsx
    │   ├── modules/
    │   │   ├── AuthModule/
    │   │   │   ├── SideContent.jsx
    │   │   │   └── index.jsx
    │   │   ├── CrudModule/
    │   │   │   └── CrudModule.jsx
    │   │   ├── DashboardModule/
    │   │   │   ├── components/
    │   │   │   │   ├── CustomerPreviewCard.jsx
    │   │   │   │   ├── PreviewCard.jsx
    │   │   │   │   ├── RecentTable/
    │   │   │   │   │   └── index.jsx
    │   │   │   │   └── SummaryCard.jsx
    │   │   │   └── index.jsx
    │   │   ├── ErpPanelModule/
    │   │   │   ├── CreateItem.jsx
    │   │   │   ├── DataTable.jsx
    │   │   │   ├── DeleteItem.jsx
    │   │   │   ├── ItemRow.jsx
    │   │   │   ├── ReadItem.jsx
    │   │   │   ├── SearchItem.jsx
    │   │   │   ├── UpdateItem.jsx
    │   │   │   └── index.jsx
    │   │   ├── InvoiceModule/
    │   │   │   ├── CreateInvoiceModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── Forms/
    │   │   │   │   └── InvoiceForm.jsx
    │   │   │   ├── InvoiceDataTableModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── ReadInvoiceModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── RecordPaymentModule/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── Payment.jsx
    │   │   │   │   │   └── RecordPayment.jsx
    │   │   │   │   └── index.jsx
    │   │   │   └── UpdateInvoiceModule/
    │   │   │       └── index.jsx
    │   │   ├── PaymentModule/
    │   │   │   ├── PaymentDataTableModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── ReadPaymentModule/
    │   │   │   │   ├── components/
    │   │   │   │   │   └── ReadItem.jsx
    │   │   │   │   └── index.jsx
    │   │   │   └── UpdatePaymentModule/
    │   │   │       ├── components/
    │   │   │       │   ├── Payment.jsx
    │   │   │       │   └── UpdatePayment.jsx
    │   │   │       └── index.jsx
    │   │   ├── ProfileModule/
    │   │   │   ├── components/
    │   │   │   │   ├── AdminInfo.jsx
    │   │   │   │   ├── PasswordModal.jsx
    │   │   │   │   ├── Profile.jsx
    │   │   │   │   ├── ProfileAdminForm.jsx
    │   │   │   │   ├── UpdateAdmin.jsx
    │   │   │   │   └── UploadImg.jsx
    │   │   │   └── index.jsx
    │   │   ├── QuoteModule/
    │   │   │   ├── CreateQuoteModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── Forms/
    │   │   │   │   └── QuoteForm.jsx
    │   │   │   ├── QuoteDataTableModule/
    │   │   │   │   └── index.jsx
    │   │   │   ├── ReadQuoteModule/
    │   │   │   │   └── index.jsx
    │   │   │   └── UpdateQuoteModule/
    │   │   │       └── index.jsx
    │   │   └── SettingModule/
    │   │       ├── CompanyLogoSettingsModule/
    │   │       │   ├── forms/
    │   │       │   │   └── AppSettingForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── CompanySettingsModule/
    │   │       │   ├── SettingsForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── FinanceSettingsModule/
    │   │       │   ├── SettingsForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── GeneralSettingsModule/
    │   │       │   ├── forms/
    │   │       │   │   └── GeneralSettingForm.jsx
    │   │       │   └── index.jsx
    │   │       ├── MoneyFormatSettingsModule/
    │   │       │   ├── SettingsForm.jsx
    │   │       │   └── index.jsx
    │   │       └── components/
    │   │           ├── SetingsSection.jsx
    │   │           ├── UpdateSettingForm.jsx
    │   │           └── UpdateSettingModule.jsx
    │   ├── pages/
    │   │   ├── About.jsx
    │   │   ├── Customer/
    │   │   │   ├── config.js
    │   │   │   └── index.jsx
    │   │   ├── ForgetPassword.jsx
    │   │   ├── Invoice/
    │   │   │   ├── InvoiceCreate.jsx
    │   │   │   ├── InvoiceRead.jsx
    │   │   │   ├── InvoiceRecordPayment.jsx
    │   │   │   ├── InvoiceUpdate.jsx
    │   │   │   └── index.jsx
    │   │   ├── Login.jsx
    │   │   ├── Logout.jsx
    │   │   ├── NotFound.jsx
    │   │   ├── Payment/
    │   │   │   ├── PaymentRead.jsx
    │   │   │   ├── PaymentUpdate.jsx
    │   │   │   └── index.jsx
    │   │   ├── Profile.jsx
    │   │   ├── ResetPassword.jsx
    │   │   └── Settings/
    │   │       ├── CompanyLogoSettings.jsx
    │   │       ├── CompanySettings.jsx
    │   │       ├── FinanceSettings.jsx
    │   │       ├── GeneralSettings.jsx
    │   │       ├── MoneyFormatSettings.jsx
    │   │       └── Settings.jsx
    │   ├── redux/
    │   │   ├── adavancedCrud/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── auth/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── crud/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── erp/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── rootReducer.js
    │   │   ├── settings/
    │   │   │   ├── actions.js
    │   │   │   ├── index.js
    │   │   │   ├── reducer.js
    │   │   │   ├── selectors.js
    │   │   │   └── types.js
    │   │   ├── store.js
    │   │   └── storePersist.js
    │   ├── request/
    │   │   ├── checkImage.js
    │   │   ├── codeMessage.js
    │   │   ├── errorHandler.js
    │   │   ├── index.js
    │   │   ├── request.js
    │   │   └── successHandler.js
    │   ├── router/
    │   │   ├── AppRouter.jsx
    │   │   ├── AuthRouter.jsx
    │   │   └── routes.jsx
    │   ├── settings/
    │   │   ├── index.jsx
    │   │   ├── useDate.jsx
    │   │   └── useMoney.jsx
    │   ├── style/
    │   │   ├── app.css
    │   │   └── partials/
    │   │       ├── auth.css
    │   │       ├── collapseBox.css
    │   │       ├── core.css
    │   │       ├── customAntd.css
    │   │       ├── erp.css
    │   │       ├── header.css
    │   │       ├── layout.css
    │   │       ├── navigation.css
    │   │       ├── rest.css
    │   │       ├── sidePanel.css
    │   │       └── transition.css
    │   └── utils/
    │       ├── calculate.js
    │       ├── color.js
    │       ├── countryList.js
    │       ├── currencyList.js
    │       ├── dataStructure.jsx
    │       ├── helpers.js
    │       ├── isBrowser.js
    │       ├── statusTagColor.js
    │       ├── tagColor.js
    │       └── valueType.js
    ├── temp.env
    └── vite.config.js
Download .txt
SYMBOL INDEX (270 symbols across 167 files)

FILE: backend/src/controllers/appControllers/clientController/index.js
  function modelController (line 6) | function modelController() {

FILE: backend/src/controllers/middlewaresControllers/createAuthMiddleware/checkAndCorrectURL.js
  function checkAndCorrectURL (line 1) | function checkAndCorrectURL(url) {

FILE: backend/src/middlewares/inventory/generateUniqueNumber.js
  function generateUniqueNumber (line 1) | function generateUniqueNumber(uniqueId, numberLength = 13) {

FILE: backend/src/server.js
  constant OPENAI_API_KEY (line 19) | const OPENAI_API_KEY = process.env.OPENAI_API_KEY;

FILE: backend/src/settings/useMoney.js
  function currencyFormat (line 13) | function currencyFormat(amount) {
  function moneyFormatter (line 30) | function moneyFormatter({ amount = 0 }) {
  function amountFormatter (line 36) | function amountFormatter({ amount = 0 }) {

FILE: backend/src/setup/reset.js
  function deleteData (line 7) | async function deleteData() {

FILE: backend/src/setup/setup.js
  function setupApp (line 10) | async function setupApp() {

FILE: frontend/src/RootApp.jsx
  function RoutApp (line 11) | function RoutApp() {

FILE: frontend/src/apps/ErpApp.jsx
  function ErpCrmApp (line 25) | function ErpCrmApp() {

FILE: frontend/src/apps/Header/HeaderContainer.jsx
  function HeaderContent (line 17) | function HeaderContent() {

FILE: frontend/src/apps/Header/UpgradeButton.jsx
  function UpgradeButton (line 9) | function UpgradeButton() {

FILE: frontend/src/apps/IdurarOs.jsx
  function IdurarOs (line 23) | function IdurarOs() {

FILE: frontend/src/apps/Navigation/NavigationContainer.jsx
  function Navigation (line 33) | function Navigation() {
  function Sidebar (line 39) | function Sidebar({ collapsible, isMobile = false }) {
  function MobileSidebar (line 181) | function MobileSidebar() {

FILE: frontend/src/components/AutoCompleteAsync/index.jsx
  function AutoCompleteAsync (line 11) | function AutoCompleteAsync({

FILE: frontend/src/components/CollapseBox/index.jsx
  function CollapseBox (line 38) | function CollapseBox({

FILE: frontend/src/components/CreateForm/index.jsx
  function CreateForm (line 13) | function CreateForm({ config, formElements, withUpload = false }) {

FILE: frontend/src/components/CrudModal/index.jsx
  function DeleteModal (line 11) | function DeleteModal({ config, children }) {

FILE: frontend/src/components/DataTable/DataTable.jsx
  function AddNewItem (line 26) | function AddNewItem({ config }) {
  function DataTable (line 42) | function DataTable({ config, extra = [] }) {

FILE: frontend/src/components/DeleteModal/index.jsx
  function DeleteModal (line 13) | function DeleteModal({ config }) {

FILE: frontend/src/components/Loading/index.jsx
  function Loading (line 4) | function Loading({ isLoading, children }) {

FILE: frontend/src/components/MoneyInputFormItem/index.jsx
  function MoneyInputFormItem (line 4) | function MoneyInputFormItem({ updatePrice, value = 0, readOnly = false }) {

FILE: frontend/src/components/MultiStepSelectAsync/index.jsx
  function fetchData (line 37) | async function fetchData() {

FILE: frontend/src/components/NotFound/index.jsx
  function NotFound (line 6) | function NotFound({ entity = '' }) {

FILE: frontend/src/components/ReadItem/index.jsx
  function ReadItem (line 15) | function ReadItem({ config }) {

FILE: frontend/src/components/SearchItem/index.jsx
  function SearchItemComponent (line 14) | function SearchItemComponent({ config, onRerender }) {
  function SearchItem (line 116) | function SearchItem({ config }) {

FILE: frontend/src/components/SelectTag/index.jsx
  function SelectTag (line 4) | function SelectTag({ options, defaultValue }) {

FILE: frontend/src/components/SidePanel/index.jsx
  function SidePanel (line 11) | function SidePanel({ config, topContent, bottomContent, fixHeaderPanel }) {

FILE: frontend/src/components/TabsContent/TabsContent.jsx
  function TabsContent (line 52) | function TabsContent({ content, defaultActiveKey, pageTitle }) {

FILE: frontend/src/components/Tag/index.jsx
  function StatusTag (line 4) | function StatusTag({ status = 'draft' }) {

FILE: frontend/src/components/UpdateForm/index.jsx
  function UpdateForm (line 14) | function UpdateForm({ config, formElements, withUpload = false }) {

FILE: frontend/src/components/Visibility/index.jsx
  function Visibility (line 1) | function Visibility({ isOpen, children }) {

FILE: frontend/src/components/outsideClick.js/demo.js
  function App (line 7) | function App() {

FILE: frontend/src/config/serverApiConfig.js
  constant API_BASE_URL (line 1) | const API_BASE_URL =
  constant BASE_URL (line 5) | const BASE_URL =
  constant WEBSITE_URL (line 10) | const WEBSITE_URL = import.meta.env.PROD
  constant DOWNLOAD_BASE_URL (line 13) | const DOWNLOAD_BASE_URL =
  constant ACCESS_TOKEN_NAME (line 17) | const ACCESS_TOKEN_NAME = 'x-auth-token';
  constant FILE_BASE_URL (line 19) | const FILE_BASE_URL = import.meta.env.VITE_FILE_BASE_URL;

FILE: frontend/src/context/adavancedCrud/index.jsx
  function AdavancedCrudContextProvider (line 8) | function AdavancedCrudContextProvider({ children }) {
  function useAdavancedCrudContext (line 15) | function useAdavancedCrudContext() {

FILE: frontend/src/context/adavancedCrud/reducer.jsx
  function contextReducer (line 25) | function contextReducer(state, action) {

FILE: frontend/src/context/adavancedCrud/types.jsx
  constant OPEN_MODAL (line 1) | const OPEN_MODAL = 'OPEN_MODAL';
  constant CLOSE_MODAL (line 2) | const CLOSE_MODAL = 'CLOSE_MODAL';
  constant OPEN_PANEL (line 4) | const OPEN_PANEL = 'OPEN_PANEL';
  constant CLOSE_PANEL (line 5) | const CLOSE_PANEL = 'CLOSE_PANEL';
  constant COLLAPSE_PANEL (line 6) | const COLLAPSE_PANEL = 'COLLAPSE_PANEL';

FILE: frontend/src/context/appContext/index.jsx
  function AppContextProvider (line 7) | function AppContextProvider({ children }) {
  function useAppContext (line 14) | function useAppContext() {

FILE: frontend/src/context/appContext/reducer.jsx
  function contextReducer (line 8) | function contextReducer(state, action) {

FILE: frontend/src/context/appContext/types.jsx
  constant OPEN_NAV_MENU (line 1) | const OPEN_NAV_MENU = 'OPEN_NAV_MENU';
  constant CLOSE_NAV_MENU (line 2) | const CLOSE_NAV_MENU = 'CLOSE_NAV_MENU';
  constant COLLAPSE_NAV_MENU (line 3) | const COLLAPSE_NAV_MENU = 'COLLAPSE_NAV_MENU';
  constant CHANGE_APP (line 4) | const CHANGE_APP = 'CHANGE_APP';
  constant DEFAULT_APP (line 5) | const DEFAULT_APP = 'DEFAULT_APP';

FILE: frontend/src/context/crud/index.jsx
  function CrudContextProvider (line 8) | function CrudContextProvider({ children }) {
  function useCrudContext (line 15) | function useCrudContext() {

FILE: frontend/src/context/crud/reducer.jsx
  function contextReducer (line 12) | function contextReducer(state, action) {

FILE: frontend/src/context/crud/types.jsx
  constant OPEN_MODAL (line 1) | const OPEN_MODAL = 'OPEN_MODAL';
  constant CLOSE_MODAL (line 2) | const CLOSE_MODAL = 'CLOSE_MODAL';
  constant OPEN_ADVANCED_BOX (line 4) | const OPEN_ADVANCED_BOX = 'OPEN_ADVANCED_BOX';
  constant CLOSE_ADVANCED_BOX (line 5) | const CLOSE_ADVANCED_BOX = 'CLOSE_ADVANCED_BOX';
  constant OPEN_EDIT_BOX (line 7) | const OPEN_EDIT_BOX = 'OPEN_EDIT_BOX';
  constant CLOSE_EDIT_BOX (line 8) | const CLOSE_EDIT_BOX = 'CLOSE_EDIT_BOX';
  constant OPEN_PANEL (line 10) | const OPEN_PANEL = 'OPEN_PANEL';
  constant CLOSE_PANEL (line 11) | const CLOSE_PANEL = 'CLOSE_PANEL';
  constant COLLAPSE_PANEL (line 12) | const COLLAPSE_PANEL = 'COLLAPSE_PANEL';
  constant OPEN_BOX (line 14) | const OPEN_BOX = 'OPEN_BOX';
  constant CLOSE_BOX (line 15) | const CLOSE_BOX = 'CLOSE_BOX';
  constant COLLAPSE_BOX (line 16) | const COLLAPSE_BOX = 'COLLAPSE_BOX';
  constant OPEN_READ_BOX (line 18) | const OPEN_READ_BOX = 'OPEN_READ_BOX';
  constant CLOSE_READ_BOX (line 19) | const CLOSE_READ_BOX = 'CLOSE_READ_BOX';
  constant COLLAPSE_READ_BOX (line 20) | const COLLAPSE_READ_BOX = 'COLLAPSE_READ_BOX';

FILE: frontend/src/context/erp/index.jsx
  function ErpContextProvider (line 8) | function ErpContextProvider({ children }) {
  function useErpContext (line 15) | function useErpContext() {

FILE: frontend/src/context/erp/reducer.jsx
  function contextReducer (line 25) | function contextReducer(state, action) {

FILE: frontend/src/context/erp/types.jsx
  constant OPEN_MODAL (line 1) | const OPEN_MODAL = 'OPEN_MODAL';
  constant CLOSE_MODAL (line 2) | const CLOSE_MODAL = 'CLOSE_MODAL';
  constant OPEN_PANEL (line 4) | const OPEN_PANEL = 'OPEN_PANEL';
  constant CLOSE_PANEL (line 5) | const CLOSE_PANEL = 'CLOSE_PANEL';
  constant COLLAPSE_PANEL (line 6) | const COLLAPSE_PANEL = 'COLLAPSE_PANEL';

FILE: frontend/src/context/profileContext/index.jsx
  function ProfileContextProvider (line 8) | function ProfileContextProvider({ children }) {
  function useProfileContext (line 15) | function useProfileContext() {

FILE: frontend/src/context/profileContext/reducer.jsx
  function contextReducer (line 15) | function contextReducer(state, action) {

FILE: frontend/src/context/profileContext/types.jsx
  constant OPEN_MODAL (line 1) | const OPEN_MODAL = 'OPEN_PASSWORD_MODAL';
  constant CLOSE_MODAL (line 2) | const CLOSE_MODAL = 'CLOSE_PASSWORD_MODAL';
  constant OPEN_PANEL (line 4) | const OPEN_PANEL = 'OPEN_PROFILE_PANEL';
  constant CLOSE_PANEL (line 5) | const CLOSE_PANEL = 'CLOSE_PROFILE_PANEL';

FILE: frontend/src/forms/AdminForm.jsx
  function AdminForm (line 19) | function AdminForm({ isUpdateForm = false, isForAdminOwner = false }) {

FILE: frontend/src/forms/AdvancedSettingsForm.jsx
  function SelectType (line 9) | function SelectType() {
  function AdvancedSettingsForm (line 58) | function AdvancedSettingsForm({ isUpdateForm = false }) {

FILE: frontend/src/forms/CurrencyForm.jsx
  function CurrencyForm (line 5) | function CurrencyForm({ isUpdateForm = false }) {

FILE: frontend/src/forms/CustomerForm.jsx
  function CustomerForm (line 6) | function CustomerForm({ isUpdateForm = false }) {

FILE: frontend/src/forms/DynamicForm/index.jsx
  function DynamicForm (line 13) | function DynamicForm({ fields, isUpdateForm = false }) {
  function FormElement (line 39) | function FormElement({ field, feedback, setFeedback }) {

FILE: frontend/src/forms/EmployeeForm.jsx
  function EmployeeForm (line 8) | function EmployeeForm() {

FILE: frontend/src/forms/ForgetPasswordForm.jsx
  function ForgetPasswordForm (line 8) | function ForgetPasswordForm() {

FILE: frontend/src/forms/InventoryForm.jsx
  function InventoryForm (line 4) | function InventoryForm() {

FILE: frontend/src/forms/LeadForm.jsx
  function LeadForm (line 5) | function LeadForm() {

FILE: frontend/src/forms/LoginForm.jsx
  function LoginForm (line 7) | function LoginForm() {

FILE: frontend/src/forms/OrderForm.jsx
  function OrderForm (line 6) | function OrderForm({ isUpdateForm = false }) {

FILE: frontend/src/forms/PaymentForm.jsx
  function PaymentForm (line 10) | function PaymentForm({ maxAmount = null, isUpdateForm = false }) {

FILE: frontend/src/forms/PaymentModeForm.jsx
  function PaymentModeForm (line 6) | function PaymentModeForm({ isUpdateForm = false }) {

FILE: frontend/src/forms/RegisterForm.jsx
  function RegisterForm (line 8) | function RegisterForm({ userLocation }) {

FILE: frontend/src/forms/ResetPasswordForm.jsx
  function ResetPasswordForm (line 7) | function ResetPasswordForm() {

FILE: frontend/src/forms/TaxForm.jsx
  function TaxForm (line 6) | function TaxForm({isUpdateForm = false}) {

FILE: frontend/src/hooks/useDebounce.jsx
  function useDebounce (line 4) | function useDebounce(fn, ms = 0, deps = []) {

FILE: frontend/src/hooks/useFetch.jsx
  function useFetchData (line 3) | function useFetchData(fetchFunction) {
  function useFetch (line 28) | function useFetch(fetchFunction) {

FILE: frontend/src/hooks/useMail.jsx
  function useMail (line 7) | function useMail({ entity }) {

FILE: frontend/src/hooks/useNetwork.jsx
  function getConnection (line 9) | function getConnection() {
  function getConnectionProperty (line 14) | function getConnectionProperty() {
  function useNetwork (line 26) | function useNetwork() {

FILE: frontend/src/hooks/useOnFetch.jsx
  function useOnFetch (line 3) | function useOnFetch() {

FILE: frontend/src/hooks/useResponsive.jsx
  function handleResize (line 13) | function handleResize() {
  function calculate (line 22) | function calculate() {
  function configResponsive (line 36) | function configResponsive(config) {
  function useResponsive (line 40) | function useResponsive() {

FILE: frontend/src/hooks/useTimeoutFn.jsx
  function useTimeoutFn (line 3) | function useTimeoutFn(fn, ms = 0) {

FILE: frontend/src/layout/AuthLayout/index.jsx
  function AuthLayout (line 7) | function AuthLayout({ sideContent, children }) {

FILE: frontend/src/layout/CrudLayout/index.jsx
  function CrudLayout (line 54) | function CrudLayout({

FILE: frontend/src/layout/DashboardLayout/index.jsx
  function DashboardLayout (line 7) | function DashboardLayout({ children }) {

FILE: frontend/src/layout/DefaultLayout/index.jsx
  function DefaultLayout (line 5) | function DefaultLayout({ children }) {

FILE: frontend/src/layout/ErpLayout/index.jsx
  function ErpLayout (line 8) | function ErpLayout({ children }) {

FILE: frontend/src/layout/SettingsLayout/index.jsx
  function SettingsLayout (line 31) | function SettingsLayout({

FILE: frontend/src/locale/Localization.jsx
  function Localization (line 3) | function Localization({ children }) {

FILE: frontend/src/modules/AuthModule/SideContent.jsx
  function SideContent (line 9) | function SideContent() {

FILE: frontend/src/modules/CrudModule/CrudModule.jsx
  function SidePanelTopContent (line 21) | function SidePanelTopContent({ config, formElements, withUpload }) {
  function FixHeaderPanel (line 88) | function FixHeaderPanel({ config }) {
  function CrudModule (line 109) | function CrudModule({ config, createForm, updateForm, withUpload = false...

FILE: frontend/src/modules/DashboardModule/components/CustomerPreviewCard.jsx
  function CustomerPreviewCard (line 5) | function CustomerPreviewCard({

FILE: frontend/src/modules/DashboardModule/components/PreviewCard.jsx
  function PreviewCard (line 92) | function PreviewCard({

FILE: frontend/src/modules/DashboardModule/components/RecentTable/index.jsx
  function RecentTable (line 13) | function RecentTable({ ...props }) {

FILE: frontend/src/modules/DashboardModule/components/SummaryCard.jsx
  function AnalyticSummaryCard (line 6) | function AnalyticSummaryCard({ title, tagColor, data, prefix, isLoading ...

FILE: frontend/src/modules/DashboardModule/index.jsx
  function DashboardModule (line 21) | function DashboardModule() {

FILE: frontend/src/modules/ErpPanelModule/CreateItem.jsx
  function SaveForm (line 27) | function SaveForm({ form }) {
  function CreateItem (line 40) | function CreateItem({ config, CreateForm }) {

FILE: frontend/src/modules/ErpPanelModule/DataTable.jsx
  function AddNewItem (line 26) | function AddNewItem({ config }) {
  function DataTable (line 41) | function DataTable({ config, extra = [] }) {

FILE: frontend/src/modules/ErpPanelModule/DeleteItem.jsx
  function Delete (line 10) | function Delete({ config }) {

FILE: frontend/src/modules/ErpPanelModule/ItemRow.jsx
  function ItemRow (line 8) | function ItemRow({ field, remove, current = null }) {

FILE: frontend/src/modules/ErpPanelModule/ReadItem.jsx
  function ReadItem (line 70) | function ReadItem({ config, selectedItem }) {

FILE: frontend/src/modules/ErpPanelModule/SearchItem.jsx
  function Search (line 13) | function Search({ config }) {

FILE: frontend/src/modules/ErpPanelModule/UpdateItem.jsx
  function SaveForm (line 22) | function SaveForm({ form, translate }) {
  function UpdateItem (line 34) | function UpdateItem({ config, UpdateForm }) {

FILE: frontend/src/modules/ErpPanelModule/index.jsx
  function ErpPanel (line 12) | function ErpPanel({ config, extra }) {

FILE: frontend/src/modules/InvoiceModule/CreateInvoiceModule/index.jsx
  function CreateInvoiceModule (line 5) | function CreateInvoiceModule({ config }) {

FILE: frontend/src/modules/InvoiceModule/Forms/InvoiceForm.jsx
  function InvoiceForm (line 22) | function InvoiceForm({ subTotal = 0, current = null }) {
  function LoadInvoiceForm (line 32) | function LoadInvoiceForm({ subTotal = 0, current = null }) {

FILE: frontend/src/modules/InvoiceModule/InvoiceDataTableModule/index.jsx
  function InvoiceDataTableModule (line 6) | function InvoiceDataTableModule({ config }) {

FILE: frontend/src/modules/InvoiceModule/ReadInvoiceModule/index.jsx
  function ReadInvoiceModule (line 13) | function ReadInvoiceModule({ config }) {

FILE: frontend/src/modules/InvoiceModule/RecordPaymentModule/components/Payment.jsx
  function Payment (line 16) | function Payment({ config, currentItem }) {

FILE: frontend/src/modules/InvoiceModule/RecordPaymentModule/components/RecordPayment.jsx
  function RecordPayment (line 15) | function RecordPayment({ config }) {

FILE: frontend/src/modules/InvoiceModule/RecordPaymentModule/index.jsx
  function RecordPaymentModule (line 11) | function RecordPaymentModule({ config }) {

FILE: frontend/src/modules/InvoiceModule/UpdateInvoiceModule/index.jsx
  function UpdateInvoiceModule (line 18) | function UpdateInvoiceModule({ config }) {

FILE: frontend/src/modules/PaymentModule/PaymentDataTableModule/index.jsx
  function PaymentDataTableModule (line 4) | function PaymentDataTableModule({ config }) {

FILE: frontend/src/modules/PaymentModule/ReadPaymentModule/components/ReadItem.jsx
  function ReadItem (line 27) | function ReadItem({ config, selectedItem }) {

FILE: frontend/src/modules/PaymentModule/ReadPaymentModule/index.jsx
  function ReadPaymentModule (line 11) | function ReadPaymentModule({ config }) {

FILE: frontend/src/modules/PaymentModule/UpdatePaymentModule/components/Payment.jsx
  function Payment (line 13) | function Payment({ config, currentItem }) {

FILE: frontend/src/modules/PaymentModule/UpdatePaymentModule/components/UpdatePayment.jsx
  function UpdatePayment (line 16) | function UpdatePayment({ config, currentInvoice }) {

FILE: frontend/src/modules/PaymentModule/UpdatePaymentModule/index.jsx
  function UpdatePaymentModule (line 12) | function UpdatePaymentModule({ config }) {

FILE: frontend/src/modules/ProfileModule/components/PasswordModal.jsx
  method validator (line 63) | validator(_, value) {

FILE: frontend/src/modules/ProfileModule/components/Profile.jsx
  function Profile (line 11) | function Profile({ config }) {

FILE: frontend/src/modules/ProfileModule/components/ProfileAdminForm.jsx
  function AdminForm (line 19) | function AdminForm({ isUpdateForm = false }) {

FILE: frontend/src/modules/ProfileModule/components/UploadImg.jsx
  function UploadImg (line 18) | function UploadImg() {

FILE: frontend/src/modules/ProfileModule/index.jsx
  function ProfileModule (line 6) | function ProfileModule({ config }) {

FILE: frontend/src/modules/QuoteModule/CreateQuoteModule/index.jsx
  function CreateQuoteModule (line 5) | function CreateQuoteModule({ config }) {

FILE: frontend/src/modules/QuoteModule/Forms/QuoteForm.jsx
  function QuoteForm (line 22) | function QuoteForm({ subTotal = 0, current = null }) {
  function LoadQuoteForm (line 32) | function LoadQuoteForm({ subTotal = 0, current = null }) {

FILE: frontend/src/modules/QuoteModule/QuoteDataTableModule/index.jsx
  function QuoteDataTableModule (line 4) | function QuoteDataTableModule({ config }) {

FILE: frontend/src/modules/QuoteModule/ReadQuoteModule/index.jsx
  function ReadQuoteModule (line 13) | function ReadQuoteModule({ config }) {

FILE: frontend/src/modules/QuoteModule/UpdateQuoteModule/index.jsx
  function UpdateQuoteModule (line 16) | function UpdateQuoteModule({ config }) {

FILE: frontend/src/modules/SettingModule/CompanyLogoSettingsModule/forms/AppSettingForm.jsx
  function AppSettingForm (line 7) | function AppSettingForm() {

FILE: frontend/src/modules/SettingModule/CompanyLogoSettingsModule/index.jsx
  function CompanyLogoSettingsModule (line 7) | function CompanyLogoSettingsModule({ config }) {

FILE: frontend/src/modules/SettingModule/CompanySettingsModule/SettingsForm.jsx
  function SettingForm (line 50) | function SettingForm() {

FILE: frontend/src/modules/SettingModule/CompanySettingsModule/index.jsx
  function CompanySettingsModule (line 6) | function CompanySettingsModule({ config }) {

FILE: frontend/src/modules/SettingModule/FinanceSettingsModule/SettingsForm.jsx
  function SettingForm (line 23) | function SettingForm() {

FILE: frontend/src/modules/SettingModule/FinanceSettingsModule/index.jsx
  function MoneyFormatSettingsModule (line 6) | function MoneyFormatSettingsModule({ config }) {

FILE: frontend/src/modules/SettingModule/GeneralSettingsModule/forms/GeneralSettingForm.jsx
  function GeneralSettingForm (line 7) | function GeneralSettingForm() {

FILE: frontend/src/modules/SettingModule/GeneralSettingsModule/index.jsx
  function GeneralSettingsModule (line 6) | function GeneralSettingsModule({ config }) {

FILE: frontend/src/modules/SettingModule/MoneyFormatSettingsModule/SettingsForm.jsx
  function SettingsForm (line 7) | function SettingsForm() {

FILE: frontend/src/modules/SettingModule/MoneyFormatSettingsModule/index.jsx
  function MoneyFormatSettingsModule (line 6) | function MoneyFormatSettingsModule({ config }) {

FILE: frontend/src/modules/SettingModule/components/SetingsSection.jsx
  function SetingsSection (line 6) | function SetingsSection({ title, description, children }) {

FILE: frontend/src/modules/SettingModule/components/UpdateSettingForm.jsx
  function UpdateSettingForm (line 12) | function UpdateSettingForm({ config, children, withUpload, uploadSetting...

FILE: frontend/src/modules/SettingModule/components/UpdateSettingModule.jsx
  function UpdateSettingModule (line 7) | function UpdateSettingModule({

FILE: frontend/src/pages/Customer/index.jsx
  function Customer (line 7) | function Customer() {

FILE: frontend/src/pages/ForgetPassword.jsx
  function postData (line 21) | async function postData(data) {

FILE: frontend/src/pages/Invoice/InvoiceCreate.jsx
  function InvoiceCreate (line 4) | function InvoiceCreate() {

FILE: frontend/src/pages/Invoice/InvoiceRead.jsx
  function InvoiceRead (line 4) | function InvoiceRead() {

FILE: frontend/src/pages/Invoice/InvoiceRecordPayment.jsx
  function InvoiceRecord (line 4) | function InvoiceRecord() {

FILE: frontend/src/pages/Invoice/InvoiceUpdate.jsx
  function InvoiceUpdate (line 4) | function InvoiceUpdate() {

FILE: frontend/src/pages/Invoice/index.jsx
  function Invoice (line 9) | function Invoice() {

FILE: frontend/src/pages/Logout.jsx
  function asyncLogout (line 12) | function asyncLogout() {

FILE: frontend/src/pages/Payment/PaymentRead.jsx
  function PaymentRead (line 4) | function PaymentRead() {

FILE: frontend/src/pages/Payment/PaymentUpdate.jsx
  function PaymentUpdate (line 4) | function PaymentUpdate() {

FILE: frontend/src/pages/Payment/index.jsx
  function Payment (line 7) | function Payment() {

FILE: frontend/src/pages/Profile.jsx
  function Profile (line 5) | function Profile() {

FILE: frontend/src/pages/Settings/CompanyLogoSettings.jsx
  function AppSettings (line 5) | function AppSettings() {

FILE: frontend/src/pages/Settings/CompanySettings.jsx
  function CompanySettings (line 5) | function CompanySettings() {

FILE: frontend/src/pages/Settings/FinanceSettings.jsx
  function FinanceSettings (line 5) | function FinanceSettings() {

FILE: frontend/src/pages/Settings/GeneralSettings.jsx
  function GeneralSettings (line 5) | function GeneralSettings() {

FILE: frontend/src/pages/Settings/MoneyFormatSettings.jsx
  function MoneyFormatSettings (line 5) | function MoneyFormatSettings() {

FILE: frontend/src/pages/Settings/Settings.jsx
  function Settings (line 20) | function Settings() {

FILE: frontend/src/redux/adavancedCrud/reducer.js
  constant INITIAL_STATE (line 3) | const INITIAL_STATE = {

FILE: frontend/src/redux/adavancedCrud/types.js
  constant RESET_STATE (line 1) | const RESET_STATE = 'ADVANCED_CRUD_RESET_STATE';
  constant CURRENT_ITEM (line 2) | const CURRENT_ITEM = 'ADVANCED_CRUD_CURRENT_ITEM';
  constant REQUEST_LOADING (line 4) | const REQUEST_LOADING = 'ADVANCED_CRUD_REQUEST_LOADING';
  constant REQUEST_SUCCESS (line 5) | const REQUEST_SUCCESS = 'ADVANCED_CRUD_REQUEST_SUCCESS';
  constant REQUEST_FAILED (line 6) | const REQUEST_FAILED = 'ADVANCED_CRUD_REQUEST_FAILED';
  constant CURRENT_ACTION (line 8) | const CURRENT_ACTION = 'ADVANCED_CRUD_CURRENT_ACTION';
  constant RESET_ACTION (line 9) | const RESET_ACTION = 'ADVANCED_CRUD_RESET_ACTION';

FILE: frontend/src/redux/auth/reducer.js
  constant INITIAL_STATE (line 3) | const INITIAL_STATE = {

FILE: frontend/src/redux/auth/types.js
  constant FAILED_REQUEST (line 1) | const FAILED_REQUEST = 'AUTH_FAILED_REQUEST';
  constant LOADING_REQUEST (line 2) | const LOADING_REQUEST = 'AUTH_LOADING_REQUEST';
  constant LOGIN_SUCCESS (line 4) | const LOGIN_SUCCESS = 'AUTH_LOGIN_SUCCESS';
  constant REGISTER_SUCCESS (line 5) | const REGISTER_SUCCESS = 'AUTH_REGISTER_SUCCESS';
  constant LOGOUT_SUCCESS (line 7) | const LOGOUT_SUCCESS = 'AUTH_LOGOUT_SUCCESS';
  constant LOGOUT_FAILED (line 8) | const LOGOUT_FAILED = 'AUTH_LOGOUT_FAILED';
  constant RESET_STATE (line 10) | const RESET_STATE = 'AUTH_RESET_STATE';
  constant REQUEST_LOADING (line 12) | const REQUEST_LOADING = 'AUTH_REQUEST_LOADING';
  constant REQUEST_SUCCESS (line 13) | const REQUEST_SUCCESS = 'AUTH_REQUEST_SUCCESS';
  constant REQUEST_FAILED (line 14) | const REQUEST_FAILED = 'AUTH_REQUEST_FAILED';

FILE: frontend/src/redux/crud/reducer.js
  constant INITIAL_KEY_STATE (line 3) | const INITIAL_KEY_STATE = {
  constant INITIAL_STATE (line 10) | const INITIAL_STATE = {

FILE: frontend/src/redux/crud/types.js
  constant RESET_STATE (line 1) | const RESET_STATE = 'CRUD_RESET_STATE';
  constant CURRENT_ITEM (line 2) | const CURRENT_ITEM = 'CRUD_CURRENT_ITEM';
  constant REQUEST_LOADING (line 4) | const REQUEST_LOADING = 'CRUD_REQUEST_LOADING';
  constant REQUEST_SUCCESS (line 5) | const REQUEST_SUCCESS = 'CRUD_REQUEST_SUCCESS';
  constant REQUEST_FAILED (line 6) | const REQUEST_FAILED = 'CRUD_REQUEST_FAILED';
  constant CURRENT_ACTION (line 8) | const CURRENT_ACTION = 'CRUD_CURRENT_ACTION';
  constant RESET_ACTION (line 9) | const RESET_ACTION = 'CRUD_RESET_ACTION';

FILE: frontend/src/redux/erp/reducer.js
  constant INITIAL_STATE (line 3) | const INITIAL_STATE = {

FILE: frontend/src/redux/erp/types.js
  constant RESET_STATE (line 1) | const RESET_STATE = 'ERP_RESET_STATE';
  constant CURRENT_ITEM (line 2) | const CURRENT_ITEM = 'ERP_CURRENT_ITEM';
  constant REQUEST_LOADING (line 4) | const REQUEST_LOADING = 'ERP_REQUEST_LOADING';
  constant REQUEST_SUCCESS (line 5) | const REQUEST_SUCCESS = 'ERP_REQUEST_SUCCESS';
  constant REQUEST_FAILED (line 6) | const REQUEST_FAILED = 'ERP_REQUEST_FAILED';
  constant CURRENT_ACTION (line 8) | const CURRENT_ACTION = 'ERP_CURRENT_ACTION';
  constant RESET_ACTION (line 9) | const RESET_ACTION = 'ERP_RESET_ACTION';

FILE: frontend/src/redux/settings/reducer.js
  constant INITIAL_SETTINGS_STATE (line 3) | const INITIAL_SETTINGS_STATE = {
  constant INITIAL_STATE (line 11) | const INITIAL_STATE = {

FILE: frontend/src/redux/settings/types.js
  constant RESET_STATE (line 1) | const RESET_STATE = 'SETTINGS_RESET_STATE';
  constant REQUEST_LOADING (line 3) | const REQUEST_LOADING = 'SETTINGS_REQUEST_LOADING';
  constant REQUEST_SUCCESS (line 4) | const REQUEST_SUCCESS = 'SETTINGS_REQUEST_SUCCESS';
  constant REQUEST_FAILED (line 5) | const REQUEST_FAILED = 'SETTINGS_REQUEST_FAILED';
  constant UPDATE_CURRENCY (line 6) | const UPDATE_CURRENCY = 'SETTINGS_UPDATE_CURRENCY';

FILE: frontend/src/redux/store.js
  constant AUTH_INITIAL_STATE (line 10) | const AUTH_INITIAL_STATE = {

FILE: frontend/src/redux/storePersist.js
  function isJsonString (line 1) | function isJsonString(str) {

FILE: frontend/src/request/checkImage.js
  function checkImage (line 3) | async function checkImage(path) {

FILE: frontend/src/request/request.js
  function findKeyByPrefix (line 8) | function findKeyByPrefix(object, prefix) {
  function includeToken (line 16) | function includeToken() {

FILE: frontend/src/router/AppRouter.jsx
  function AppRouter (line 10) | function AppRouter() {

FILE: frontend/src/router/AuthRouter.jsx
  function AuthRouter (line 11) | function AuthRouter() {

FILE: frontend/src/settings/useMoney.jsx
  function currencyFormat (line 15) | function currencyFormat({ amount, currency_code = money_format_state?.cu...
  function moneyFormatter (line 32) | function moneyFormatter({ amount = 0, currency_code = money_format_state...
  function amountFormatter (line 38) | function amountFormatter({ amount = 0, currency_code = money_format_stat...
  function moneyRowFormatter (line 42) | function moneyRowFormatter({ amount = 0, currency_code = money_format_st...

FILE: frontend/src/utils/dataStructure.jsx
  function dataForTable (line 23) | function dataForTable({ fields, translate, moneyFormatter, dateFormat }) {
  function getRandomColor (line 208) | function getRandomColor() {

FILE: frontend/src/utils/helpers.js
  function get (line 1) | function get(obj, key) {
  function has (line 29) | function has(obj, key) {
  function valueByString (line 42) | function valueByString(obj, string, devider) {
  function toFormData (line 57) | function toFormData(form) {
  function formatDate (line 83) | function formatDate(param) {
  function formatDatetime (line 103) | function formatDatetime(param) {
Condensed preview — 429 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (938K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 834,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/custom.md",
    "chars": 126,
    "preview": "---\nname: Custom issue template\nabout: Describe this issue template's purpose here.\ntitle: ''\nlabels: ''\nassignees: ''\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 770,
    "preview": "## Description\n\nPlease provide a brief description of the changes or additions made in this pull request.\n\n## Related Is"
  },
  {
    "path": ".github/workflows/CODEOWNERS",
    "chars": 79,
    "preview": "# Default reviewers \n* @salahlalami @polymahh @onfranciis @Ando22 @Fernando7181"
  },
  {
    "path": ".github/workflows/codesee-arch-diagram.yml",
    "chars": 549,
    "preview": "# This workflow was added by CodeSee. Learn more at https://codesee.io/\n# This is v2.0 of this workflow file\non:\n  push:"
  },
  {
    "path": ".github/workflows/github-repo-stats.yml",
    "chars": 524,
    "preview": "name: github-repo-stats\n\non:\n  schedule:\n    # Run this once per day, towards the end of the day for keeping the most\n  "
  },
  {
    "path": "CODE-OF-CONDUCT.md",
    "chars": 5242,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2612,
    "preview": "# Contributing Guidelines\n\nWelcome to the [idurar-erp-crm](<[idurar-erp-crm](https://github.com/idurar/idurar-erp-crm)>)"
  },
  {
    "path": "INSTALLATION-INSTRUCTIONS.md",
    "chars": 3662,
    "preview": "## Getting started\n\n#### Step 1: Clone the repository\n\n```bash\ngit clone https://github.com/idurar/idurar-erp-crm.git\n``"
  },
  {
    "path": "LICENSE",
    "chars": 34230,
    "preview": "GNU AFFERO GENERAL PUBLIC LICENSE\nVersion 3, 19 November 2007\n\nCopyright (C) 2007 Free Software Foundation, Inc. <https:"
  },
  {
    "path": "README.md",
    "chars": 3505,
    "preview": "<div align=\"center\">\n    <a href=\"https://www.idurarapp.com/\">\n  <img src=\"https://avatars.githubusercontent.com/u/50052"
  },
  {
    "path": "SECURITY.md",
    "chars": 2089,
    "preview": "# Security Policy\n\n## Supported Releases\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 2.0.1   | "
  },
  {
    "path": "backend/.eslintrc.js",
    "chars": 230,
    "preview": "module.exports = {\n  env: {\n    browser: true,\n    es2020: true,\n    node: true,\n  },\n  extends: 'eslint:recommended',\n "
  },
  {
    "path": "backend/.gitignore",
    "chars": 62,
    "preview": "node_modules/\n*.zip\n.DS_Store\n.idea\nnotes.md\n.env.local\n\n*.pdf"
  },
  {
    "path": "backend/.prettierignore",
    "chars": 47,
    "preview": "# Ignore artifacts:\nbuild\ncoverage\nnode_modules"
  },
  {
    "path": "backend/.prettierrc",
    "chars": 106,
    "preview": "{\n  \"printWidth\": 100,\n  \"trailingComma\": \"es5\",\n  \"tabWidth\": 2,\n  \"semi\": true,\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": "backend/.vscode/settings.json",
    "chars": 278,
    "preview": "{\n  \"editor.formatOnPaste\": true,\n  \"editor.formatOnSave\": true,\n  \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n"
  },
  {
    "path": "backend/jsconfig.json",
    "chars": 126,
    "preview": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \"src\",\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    }\n  },\n  \"exclude\": [\"node_module"
  },
  {
    "path": "backend/package.json",
    "chars": 1592,
    "preview": "{\n  \"name\": \"idurar-erp-crm\",\n  \"version\": \"4.1.0\",\n  \"engines\": {\n    \"npm\": \"10.2.4\",\n    \"node\": \"20.9.0\"\n  },\n  \"scr"
  },
  {
    "path": "backend/src/app.js",
    "chars": 1489,
    "preview": "const express = require('express');\n\nconst cors = require('cors');\nconst compression = require('compression');\n\nconst co"
  },
  {
    "path": "backend/src/controllers/appControllers/clientController/index.js",
    "chars": 416,
    "preview": "const mongoose = require('mongoose');\nconst createCRUDController = require('@/controllers/middlewaresControllers/createC"
  },
  {
    "path": "backend/src/controllers/appControllers/clientController/summary.js",
    "chars": 2541,
    "preview": "const mongoose = require('mongoose');\nconst moment = require('moment');\n\nconst InvoiceModel = mongoose.model('Invoice');"
  },
  {
    "path": "backend/src/controllers/appControllers/index.js",
    "chars": 1105,
    "preview": "const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');\nconst { routesList } "
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/create.js",
    "chars": 1881,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Invoice');\n\nconst { calculate } = require('@/helper"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/index.js",
    "chars": 623,
    "preview": "const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');\nconst methods = creat"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/paginatedList.js",
    "chars": 1610,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Invoice');\n\nconst paginatedList = async (req, res) "
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/read.js",
    "chars": 659,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Invoice');\n\nconst read = async (req, res) => {\n  //"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/remove.js",
    "chars": 793,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Invoice');\nconst ModelPayment = mongoose.model('Pay"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/schemaValidate.js",
    "chars": 819,
    "preview": "const Joi = require('joi');\nconst schema = Joi.object({\n  client: Joi.alternatives().try(Joi.string(), Joi.object()).req"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/sendMail.js",
    "chars": 276,
    "preview": "const fs = require('fs');\n\nconst mongoose = require('mongoose');\n\nconst mail = async (req, res) => {\n  return res.status"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/summary.js",
    "chars": 4603,
    "preview": "const mongoose = require('mongoose');\nconst moment = require('moment');\n\nconst Model = mongoose.model('Invoice');\n\nconst"
  },
  {
    "path": "backend/src/controllers/appControllers/invoiceController/update.js",
    "chars": 2112,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Invoice');\n\nconst custom = require('@/controllers/p"
  },
  {
    "path": "backend/src/controllers/appControllers/paymentController/create.js",
    "chars": 2155,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Payment');\nconst Invoice = mongoose.model('Invoice'"
  },
  {
    "path": "backend/src/controllers/appControllers/paymentController/index.js",
    "chars": 490,
    "preview": "const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');\nconst methods = creat"
  },
  {
    "path": "backend/src/controllers/appControllers/paymentController/remove.js",
    "chars": 1685,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Payment');\nconst Invoice = mongoose.model('Invoice'"
  },
  {
    "path": "backend/src/controllers/appControllers/paymentController/sendMail.js",
    "chars": 210,
    "preview": "const mail = async (req, res) => {\n  return res.status(200).json({\n    success: true,\n    result: null,\n    message: 'Pl"
  },
  {
    "path": "backend/src/controllers/appControllers/paymentController/summary.js",
    "chars": 1537,
    "preview": "const mongoose = require('mongoose');\nconst moment = require('moment');\n\nconst Model = mongoose.model('Payment');\nconst "
  },
  {
    "path": "backend/src/controllers/appControllers/paymentController/update.js",
    "chars": 2362,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Payment');\nconst Invoice = mongoose.model('Invoice'"
  },
  {
    "path": "backend/src/controllers/coreControllers/adminAuth/index.js",
    "chars": 147,
    "preview": "const createAuthMiddleware = require('@/controllers/middlewaresControllers/createAuthMiddleware');\nmodule.exports = crea"
  },
  {
    "path": "backend/src/controllers/coreControllers/adminController/index.js",
    "chars": 147,
    "preview": "const createUserController = require('@/controllers/middlewaresControllers/createUserController');\nmodule.exports = crea"
  },
  {
    "path": "backend/src/controllers/coreControllers/settingController/index.js",
    "chars": 780,
    "preview": "const createCRUDController = require('@/controllers/middlewaresControllers/createCRUDController');\nconst crudController "
  },
  {
    "path": "backend/src/controllers/coreControllers/settingController/listAll.js",
    "chars": 650,
    "preview": "const mongoose = require('mongoose');\nconst Model = mongoose.model('Setting');\n\nconst listAll = async (req, res) => {\n  "
  },
  {
    "path": "backend/src/controllers/coreControllers/settingController/listBySettingKey.js",
    "chars": 1128,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst listBySettingKey = async (req, re"
  },
  {
    "path": "backend/src/controllers/coreControllers/settingController/readBySettingKey.js",
    "chars": 885,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst readBySettingKey = async (req, re"
  },
  {
    "path": "backend/src/controllers/coreControllers/settingController/updateBySettingKey.js",
    "chars": 1128,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst updateBySettingKey = async (req, "
  },
  {
    "path": "backend/src/controllers/coreControllers/settingController/updateManySetting.js",
    "chars": 1396,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst updateManySetting = async (req, r"
  },
  {
    "path": "backend/src/controllers/coreControllers/setup.js",
    "chars": 2654,
    "preview": "require('dotenv').config({ path: '.env' });\nrequire('dotenv').config({ path: '.env.local' });\nconst { globSync } = requi"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/authUser.js",
    "chars": 1591,
    "preview": "const bcrypt = require('bcryptjs');\nconst jwt = require('jsonwebtoken');\n\nconst authUser = async (req, res, { user, data"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/checkAndCorrectURL.js",
    "chars": 392,
    "preview": "function checkAndCorrectURL(url) {\n  // detect if it has http or https:\n  const hasHttps = url.startsWith('https://');\n\n"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/forgetPassword.js",
    "chars": 2037,
    "preview": "const Joi = require('joi');\n\nconst mongoose = require('mongoose');\n\nconst checkAndCorrectURL = require('./checkAndCorrec"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/index.js",
    "chars": 854,
    "preview": "const isValidAuthToken = require('./isValidAuthToken');\nconst login = require('./login');\nconst logout = require('./logo"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/isValidAuthToken.js",
    "chars": 2063,
    "preview": "const jwt = require('jsonwebtoken');\n\nconst mongoose = require('mongoose');\n\nconst isValidAuthToken = async (req, res, n"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/login.js",
    "chars": 1486,
    "preview": "const Joi = require('joi');\n\nconst mongoose = require('mongoose');\n\nconst authUser = require('./authUser');\n\nconst login"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/logout.js",
    "chars": 802,
    "preview": "const mongoose = require('mongoose');\n\nconst logout = async (req, res, { userModel }) => {\n  const UserPassword = mongoo"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/resetPassword.js",
    "chars": 3068,
    "preview": "const jwt = require('jsonwebtoken');\nconst bcrypt = require('bcryptjs');\nconst Joi = require('joi');\nconst mongoose = re"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createAuthMiddleware/sendMail.js",
    "chars": 537,
    "preview": "const { passwordVerfication } = require('@/emailTemplate/emailVerfication');\n\nconst { Resend } = require('resend');\n\ncon"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/create.js",
    "chars": 379,
    "preview": "const create = async (Model, req, res) => {\n  // Creating a new document in the collection\n  req.body.removed = false;\n "
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/filter.js",
    "chars": 728,
    "preview": "const filter = async (Model, req, res) => {\n  if (req.query.filter === undefined || req.query.equal === undefined) {\n   "
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/index.js",
    "chars": 1180,
    "preview": "const { modelsFiles } = require('@/models/utils');\n\nconst mongoose = require('mongoose');\n\nconst create = require('./cre"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/listAll.js",
    "chars": 844,
    "preview": "const listAll = async (Model, req, res) => {\n  const sort = req.query.sort || 'desc';\n  const enabled = req.query.enable"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/paginatedList.js",
    "chars": 1881,
    "preview": "const paginatedList = async (Model, req, res) => {\n  const page = req.query.page || 1;\n  const limit = parseInt(req.quer"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/read.js",
    "chars": 545,
    "preview": "const read = async (Model, req, res) => {\n  // Find document by id\n  const result = await Model.findOne({\n    _id: req.p"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/remove.js",
    "chars": 734,
    "preview": "const remove = async (Model, req, res) => {\n  // Find the document by id and delete it\n  let updates = {\n    removed: tr"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/search.js",
    "chars": 1095,
    "preview": "const search = async (Model, req, res) => {\n  // console.log(req.query.fields)\n  // if (req.query.q === undefined || req"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/summary.js",
    "chars": 795,
    "preview": "const summary = async (Model, req, res) => {\n  //  Query the database for a list of all results\n  const countPromise = M"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createCRUDController/update.js",
    "chars": 674,
    "preview": "const update = async (Model, req, res) => {\n  // Find document by id and updates with the required fields\n  req.body.rem"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createUserController/index.js",
    "chars": 678,
    "preview": "const read = require('./read');\nconst updateProfile = require('./updateProfile');\n\nconst updatePassword = require('./upd"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createUserController/read.js",
    "chars": 873,
    "preview": "const mongoose = require('mongoose');\n\nconst read = async (userModel, req, res) => {\n  const User = mongoose.model(userM"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createUserController/updatePassword.js",
    "chars": 1545,
    "preview": "const mongoose = require('mongoose');\nconst bcrypt = require('bcryptjs');\nconst { generate: uniqueId } = require('shorti"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createUserController/updateProfile.js",
    "chars": 1682,
    "preview": "const mongoose = require('mongoose');\n\nconst updateProfile = async (userModel, req, res) => {\n  const User = mongoose.mo"
  },
  {
    "path": "backend/src/controllers/middlewaresControllers/createUserController/updateProfilePassword.js",
    "chars": 1773,
    "preview": "const mongoose = require('mongoose');\nconst bcrypt = require('bcryptjs');\n\nconst { generate: uniqueId } = require('short"
  },
  {
    "path": "backend/src/controllers/pdfController/index.js",
    "chars": 2220,
    "preview": "const pug = require('pug');\nconst fs = require('fs');\nconst moment = require('moment');\nlet pdf = require('html-pdf');\nc"
  },
  {
    "path": "backend/src/emailTemplate/SendEmailTemplate.js",
    "chars": 7553,
    "preview": "exports.SendInvoice = ({ title = 'Invoice from Idurar', name = '', time = new Date() }) => {\n  return `\n    <div>\n\n     "
  },
  {
    "path": "backend/src/emailTemplate/emailVerfication.js",
    "chars": 2168,
    "preview": "exports.passwordVerfication = ({\n  title = 'Reset your Password',\n  name = '',\n  link = '',\n  time = new Date(),\n}) => {"
  },
  {
    "path": "backend/src/handlers/downloadHandler/downloadPdf.js",
    "chars": 2220,
    "preview": "const custom = require('@/controllers/pdfController');\nconst mongoose = require('mongoose');\n\nmodule.exports = downloadP"
  },
  {
    "path": "backend/src/handlers/errorHandlers.js",
    "chars": 2055,
    "preview": "/*\r\n  Catch Errors Handler\r\n\r\n  With async/await, you need some way to catch errors\r\n  Instead of using try{} catch(e) {"
  },
  {
    "path": "backend/src/helpers.js",
    "chars": 1696,
    "preview": "/*\n  This is a file of data and helper functions that we can expose and use in our templating function\n*/\n\n// FS is a bu"
  },
  {
    "path": "backend/src/locale/languages.js",
    "chars": 21,
    "preview": "module.exports = [];\n"
  },
  {
    "path": "backend/src/locale/translation/en_us.js",
    "chars": 12958,
    "preview": "module.exports = {\n  sign_up: 'Sign Up',\n  manage_your_company_with: 'Manage Your Company With',\n  all_in_one_tool: 'All"
  },
  {
    "path": "backend/src/locale/useLanguage.js",
    "chars": 1056,
    "preview": "const { readBySettingKey } = require('@/middlewares/settings');\n\nconst getLabel = (lang, key) => {\n  try {\n    const low"
  },
  {
    "path": "backend/src/middlewares/inventory/generateUniqueNumber.js",
    "chars": 613,
    "preview": "function generateUniqueNumber(uniqueId, numberLength = 13) {\n  const currentDate = new Date();\n  const year = (currentDa"
  },
  {
    "path": "backend/src/middlewares/inventory/index.js",
    "chars": 122,
    "preview": "const generateUniqueNumber = require('../inventory/generateUniqueNumber');\n\nmodule.exports = {\n  generateUniqueNumber,\n}"
  },
  {
    "path": "backend/src/middlewares/serverData.js",
    "chars": 355,
    "preview": "const mongoose = require('mongoose');\nexports.getData = ({ model }) => {\n  const Model = mongoose.model(model);\n  const "
  },
  {
    "path": "backend/src/middlewares/settings/increaseBySettingKey.js",
    "chars": 686,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst increaseBySettingKey = async ({ s"
  },
  {
    "path": "backend/src/middlewares/settings/index.js",
    "chars": 482,
    "preview": "const listBySettingKey = require('./listBySettingKey');\nconst readBySettingKey = require('./readBySettingKey');\nconst li"
  },
  {
    "path": "backend/src/middlewares/settings/listAllSettings.js",
    "chars": 411,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst listAllSettings = async () => {\n "
  },
  {
    "path": "backend/src/middlewares/settings/listBySettingKey.js",
    "chars": 677,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst listBySettingKey = async ({ setti"
  },
  {
    "path": "backend/src/middlewares/settings/loadSettings.js",
    "chars": 316,
    "preview": "const listAllSettings = require('./listAllSettings');\n\nconst loadSettings = async () => {\n  const allSettings = {};\n  co"
  },
  {
    "path": "backend/src/middlewares/settings/readBySettingKey.js",
    "chars": 512,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst readBySettingKey = async ({ setti"
  },
  {
    "path": "backend/src/middlewares/settings/updateBySettingKey.js",
    "chars": 699,
    "preview": "const mongoose = require('mongoose');\n\nconst Model = mongoose.model('Setting');\n\nconst updateBySettingKey = async ({ set"
  },
  {
    "path": "backend/src/middlewares/uploadMiddleware/DoSingleStorage.js",
    "chars": 2962,
    "preview": "require('dotenv').config({ path: '.env' });\nrequire('dotenv').config({ path: '.env.local' });\n\nconst path = require('pat"
  },
  {
    "path": "backend/src/middlewares/uploadMiddleware/LocalSingleStorage.js",
    "chars": 1855,
    "preview": "const multer = require('multer');\nconst path = require('path');\nconst { slugify } = require('transliteration');\n\nconst f"
  },
  {
    "path": "backend/src/middlewares/uploadMiddleware/index.js",
    "chars": 190,
    "preview": "const singleStorageUpload = require('./singleStorageUpload');\nconst LocalSingleStorage = require('./LocalSingleStorage')"
  },
  {
    "path": "backend/src/middlewares/uploadMiddleware/singleStorageUpload.js",
    "chars": 1855,
    "preview": "const multer = require('multer');\nconst path = require('path');\nconst { slugify } = require('transliteration');\n\nconst f"
  },
  {
    "path": "backend/src/middlewares/uploadMiddleware/utils/LocalfileFilter.js",
    "chars": 2395,
    "preview": "const fileFilter =\n  (type = 'default') =>\n  (req, file, cb) => {\n    // array containing all the possible file types\n  "
  },
  {
    "path": "backend/src/middlewares/uploadMiddleware/utils/fileFilterMiddleware.js",
    "chars": 2091,
    "preview": "const fileFilterMiddleware = ({ type = 'default', mimetype }) => {\n  // array containing all the possible file types\n  c"
  },
  {
    "path": "backend/src/models/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "backend/src/models/appModels/Client.js",
    "chars": 660,
    "preview": "const mongoose = require('mongoose');\n\nconst schema = new mongoose.Schema({\n  removed: {\n    type: Boolean,\n    default:"
  },
  {
    "path": "backend/src/models/appModels/Invoice.js",
    "chars": 3109,
    "preview": "const mongoose = require('mongoose');\n\nconst invoiceSchema = new mongoose.Schema({\n  removed: {\n    type: Boolean,\n    d"
  },
  {
    "path": "backend/src/models/appModels/Payment.js",
    "chars": 1060,
    "preview": "const mongoose = require('mongoose');\n\nconst paymentSchema = new mongoose.Schema({\n  removed: {\n    type: Boolean,\n    d"
  },
  {
    "path": "backend/src/models/coreModels/Admin.js",
    "chars": 624,
    "preview": "const mongoose = require('mongoose');\nconst Schema = mongoose.Schema;\n\nconst adminSchema = new Schema({\n  removed: {\n   "
  },
  {
    "path": "backend/src/models/coreModels/AdminPassword.js",
    "chars": 1068,
    "preview": "const mongoose = require('mongoose');\nconst Schema = mongoose.Schema;\n\nconst bcrypt = require('bcryptjs');\n\nconst AdminP"
  },
  {
    "path": "backend/src/models/coreModels/Setting.js",
    "chars": 671,
    "preview": "const mongoose = require('mongoose');\n\nconst settingSchema = new mongoose.Schema({\n  removed: {\n    type: Boolean,\n    d"
  },
  {
    "path": "backend/src/models/coreModels/Upload.js",
    "chars": 1144,
    "preview": "const mongoose = require('mongoose');\r\n\r\nconst uploadSchema = new mongoose.Schema({\r\n  removed: {\r\n    type: Boolean,\r\n "
  },
  {
    "path": "backend/src/models/utils/index.js",
    "chars": 1480,
    "preview": "const { basename, extname } = require('path');\nconst { globSync } = require('glob');\n\nconst appModelsFiles = globSync('."
  },
  {
    "path": "backend/src/pdf/Invoice.pug",
    "chars": 7436,
    "preview": "doctype html\nhtml\n  head\n    link(rel=\"shortcut icon\" type=\"image/png\" href=\"/images/icons/favicon.png\")\n    meta(name=\""
  },
  {
    "path": "backend/src/pdf/Offer.pug",
    "chars": 7426,
    "preview": "doctype html\nhtml\n  head\n    link(rel=\"shortcut icon\" type=\"image/png\" href=\"/images/icons/favicon.png\")\n    meta(name=\""
  },
  {
    "path": "backend/src/pdf/Payment.pug",
    "chars": 6578,
    "preview": "doctype html\nhtml\n  head\n    link(rel=\"shortcut icon\" type=\"image/png\" href=\"/images/icons/favicon.png\")\n    meta(name=\""
  },
  {
    "path": "backend/src/pdf/Quote.pug",
    "chars": 7434,
    "preview": "doctype html\nhtml\n  head\n    link(rel=\"shortcut icon\" type=\"image/png\" href=\"/images/icons/favicon.png\")\n    meta(name=\""
  },
  {
    "path": "backend/src/routes/appRoutes/appApi.js",
    "chars": 1434,
    "preview": "const express = require('express');\nconst { catchErrors } = require('@/handlers/errorHandlers');\nconst router = express."
  },
  {
    "path": "backend/src/routes/coreRoutes/coreApi.js",
    "chars": 2382,
    "preview": "const express = require('express');\n\nconst { catchErrors } = require('@/handlers/errorHandlers');\n\nconst router = expres"
  },
  {
    "path": "backend/src/routes/coreRoutes/coreAuth.js",
    "chars": 531,
    "preview": "const express = require('express');\n\nconst router = express.Router();\n\nconst { catchErrors } = require('@/handlers/error"
  },
  {
    "path": "backend/src/routes/coreRoutes/coreDownloadRouter.js",
    "chars": 579,
    "preview": "const downloadPdf = require('@/handlers/downloadHandler/downloadPdf');\nconst express = require('express');\n\nconst router"
  },
  {
    "path": "backend/src/routes/coreRoutes/corePublicRouter.js",
    "chars": 1431,
    "preview": "const express = require('express');\nconst router = express.Router();\n\nconst path = require('path');\nconst { isPathInside"
  },
  {
    "path": "backend/src/server.js",
    "chars": 1187,
    "preview": "require('module-alias/register');\nconst mongoose = require('mongoose');\nconst { globSync } = require('glob');\nconst path"
  },
  {
    "path": "backend/src/settings/index.js",
    "chars": 194,
    "preview": "const useDate = require('./useDate');\nconst useMoney = require('./useMoney');\nconst useAppSettings = require('./useAppSe"
  },
  {
    "path": "backend/src/settings/useAppSettings.js",
    "chars": 229,
    "preview": "const useAppSettings = () => {\n  let settings = {};\n  settings['idurar_app_email'] = 'noreply@idurarapp.com';\n  settings"
  },
  {
    "path": "backend/src/settings/useDate.js",
    "chars": 192,
    "preview": "const useDate = ({ settings }) => {\n  const { idurar_app_date_format } = settings;\n\n  const dateFormat = idurar_app_date"
  },
  {
    "path": "backend/src/settings/useMoney.js",
    "chars": 1183,
    "preview": "const currency = require('currency.js');\n\nconst useMoney = ({ settings }) => {\n  const {\n    currency_symbol,\n    curren"
  },
  {
    "path": "backend/src/setup/defaultSettings/appSettings.json",
    "chars": 1340,
    "preview": "[\n  {\n    \"settingCategory\": \"app_settings\",\n    \"settingKey\": \"idurar_app_date_format\",\n    \"settingValue\": \"DD/MM/YYYY"
  },
  {
    "path": "backend/src/setup/defaultSettings/clientSettings.json",
    "chars": 1589,
    "preview": "[\n  {\n    \"settingCategory\": \"client_settings\",\n    \"settingKey\": \"client_type\",\n    \"settingValue\": [\"people\", \"company"
  },
  {
    "path": "backend/src/setup/defaultSettings/companySettings.json",
    "chars": 2041,
    "preview": "[\n  {\n    \"settingCategory\": \"company_settings\",\n    \"settingKey\": \"company_name\",\n    \"settingValue\": \"COMPANY Name\",\n "
  },
  {
    "path": "backend/src/setup/defaultSettings/financeSettings.json",
    "chars": 1131,
    "preview": "[\n  {\n    \"settingCategory\": \"finance_settings\",\n    \"settingKey\": \"last_invoice_number\",\n    \"settingValue\": 0,\n    \"va"
  },
  {
    "path": "backend/src/setup/defaultSettings/invoiceSettings.json",
    "chars": 738,
    "preview": "[\n  {\n    \"settingCategory\": \"invoice_settings\",\n    \"settingKey\": \"invoice_show_product_tax\",\n    \"settingValue\": false"
  },
  {
    "path": "backend/src/setup/defaultSettings/moneyFormatSettings.json",
    "chars": 1174,
    "preview": "[\n  {\n    \"settingCategory\": \"money_format_settings\",\n    \"settingKey\": \"default_currency_code\",\n    \"settingValue\": \"US"
  },
  {
    "path": "backend/src/setup/defaultSettings/quoteSettings.json",
    "chars": 774,
    "preview": "[\n  {\n    \"settingCategory\": \"quote_settings\",\n    \"settingKey\": \"quote_show_product_tax\",\n    \"settingValue\": false,\n  "
  },
  {
    "path": "backend/src/setup/reset.js",
    "chars": 879,
    "preview": "require('dotenv').config({ path: '.env' });\nrequire('dotenv').config({ path: '.env.local' });\n\nconst mongoose = require("
  },
  {
    "path": "backend/src/setup/setup.js",
    "chars": 2161,
    "preview": "require('dotenv').config({ path: '.env' });\nrequire('dotenv').config({ path: '.env.local' });\nconst { globSync } = requi"
  },
  {
    "path": "backend/src/setup/setupConfig.json",
    "chars": 2596,
    "preview": "[\n  {\n    \"setupCategory\": \"setup_config\",\n    \"setupKey\": \"idurar_app_version\",\n    \"setupValue\": \"3.0.0\",\n    \"valueTy"
  },
  {
    "path": "backend/src/utils/countryList.js",
    "chars": 16457,
    "preview": "const listTimeZones = [\n  {\n    code: 'AF',\n    countryName: 'Afghanistan',\n    timeZones: ['Asia/Kabul'],\n  },\n  {\n    "
  },
  {
    "path": "backend/src/utils/currency.js",
    "chars": 1200,
    "preview": "const currencyList = [\n  'USD',\n  'CAD',\n  'EUR',\n  'AED',\n  'AFN',\n  'ALL',\n  'AMD',\n  'ARS',\n  'AUD',\n  'AZN',\n  'BAM'"
  },
  {
    "path": "backend/src/utils/currencyList.js",
    "chars": 494,
    "preview": "exports.currencyList = [\n  {\n    currency_symbol: '$',\n    currency_position: 'before',\n    decimal_sep: '.',\n    thousa"
  },
  {
    "path": "backend/src/utils/is-path-inside.js",
    "chars": 352,
    "preview": "const path = require('path');\n\n// is implementation of is-path-inside npm package\n\nexports.isPathInside = (childPath, pa"
  },
  {
    "path": "doc/README.fr.md",
    "chars": 5963,
    "preview": "#### French Translation\n\n\n<div align=\"center\">\n    <a href=\"https://www.idurarapp.com/\">\n  <img src=\"https://avatars.git"
  },
  {
    "path": "doc/README.sp.md",
    "chars": 5801,
    "preview": "#### Spanish Translation\n\n\n<div align=\"center\">\n    <a href=\"https://www.idurarapp.com/\">\n  <img src=\"https://avatars.gi"
  },
  {
    "path": "features/ar_eg_ملف_مفتوح_المصدر_مجاني_للبرمجيات_ERP_CRM.md",
    "chars": 3370,
    "preview": "# IDURAR برنامج إدارة الموارد التخطيطية وعلاقات العملاء مفتوح المصدر\n\nGitHub: [https://github.com/idurar/idurar-erp-crm]"
  },
  {
    "path": "features/bg_bg_свободен_отворен_източник_erp_crm_софтуер.md",
    "chars": 4544,
    "preview": "# IDURAR Софтуер за управление на отворен код ERP & CRM\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://gith"
  },
  {
    "path": "features/bn_bd_ফ্রি_ওপেন_সোর্স_ইআরপি_সিআরএম_সফটওয়্যার.md",
    "chars": 4162,
    "preview": "# IDURAR ওপেন-সোর্স ইআরপি এবং সিআরএম সফটওয়্যার\n\nগিটহাব: [https://github.com/idurar/idurar-erp-crm](https://github.com/i"
  },
  {
    "path": "features/ca_es_software_erp_crm_de_codi_obert_gratuït.md",
    "chars": 4580,
    "preview": "# IDURAR Software de ERP y CRM de código abierto\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/"
  },
  {
    "path": "features/cs_cz_volný_otevřený_zdroj_erp_crm_software.md",
    "chars": 3984,
    "preview": "# IDURAR Open-Source ERP & CRM Software\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/da_dk_gratis_åben_kilde_erp_crm_software.md",
    "chars": 3997,
    "preview": "# IDURAR Åben-Source ERP & CRM-Software\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/de_de_frei_offene_quelle_erp_crm_software.md",
    "chars": 4728,
    "preview": "# IDURAR Open-Source ERP & CRM Software\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/el_gr_ελεύθερο_ανοικτο_πηγαίο_erp_crm_λογισμικό.md",
    "chars": 4790,
    "preview": "# IDURAR Λογισμικό ERP & CRM ανοιχτού κώδικα\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idur"
  },
  {
    "path": "features/en_us_free_open_source_erp_crm_software.md",
    "chars": 4081,
    "preview": "# IDURAR Open-Source ERP & CRM Software\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/es_es_software_erp_crm_de_código_abierto_y_gratis.md",
    "chars": 4633,
    "preview": "# IDURAR Software de ERP y CRM de código abierto\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/"
  },
  {
    "path": "features/et_ee_tasuta_avatud_lähtekoodiga_erp_crm_tarkvara.md",
    "chars": 4025,
    "preview": "# IDURAR Open-Source ERP & CRM Tarkvara\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/fa_ir_رایگان_منبع_باز_نرم‌افزار_مدیریت_مالی_و_ارتباطات.md",
    "chars": 3337,
    "preview": "# نرم‌افزار متن‌باز IDURAR ERP & CRM\n\nگیت‌هاب: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idur"
  },
  {
    "path": "features/fi_fi_ilmainen_avoin_lähdekoodi_erp_crm_ohjelmisto.md",
    "chars": 4118,
    "preview": "# IDURAR Avoin lähdekoodin ERP- ja CRM-ohjelmisto\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com"
  },
  {
    "path": "features/fr_fr_gratuit_logiciel_erp_crm_open_source.md",
    "chars": 4839,
    "preview": "# IDURAR Logiciel ERP & CRM Open-Source\n\nGitHub : [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/i"
  },
  {
    "path": "features/hi_in_मुफ्त_खुला_स्रोत_ईआरपी_सीआरएम_सॉफ़्टवेयर.md",
    "chars": 4130,
    "preview": "# IDURAR ओपन-सोर्स ईआरपी और सीआरएम सॉफ्टवेयर\n\nगिटहब: [https://github.com/idurar/idurar-erp-crm](https://github.com/idura"
  },
  {
    "path": "features/hr_hr_besplatni_otvoreni_izvor_erp_crm_softver.md",
    "chars": 4394,
    "preview": "# IDURAR Open-Source ERP & CRM Softver\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idu"
  },
  {
    "path": "features/hu_hu_ingyenes_nyílt_forráskódú_erp_crm_szoftver.md",
    "chars": 4764,
    "preview": "# IDURAR Nyílt forráskódú ERP & CRM szoftver\n\nGitHub : [https://github.com/idurar/idurar-erp-crm](https://github.com/idu"
  },
  {
    "path": "features/id_id_perangkat_lunak_erp_crm_sumber_terbuka_gratis.md",
    "chars": 4292,
    "preview": "# Perangkat Lunak ERP & CRM Sumber Terbuka IDURAR\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com"
  },
  {
    "path": "features/it_it_software_erp_crm_open_source_gratuito.md",
    "chars": 4419,
    "preview": "# IDURAR Software ERP e CRM Open-Source\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/ja_jp_フリーオープンソースERP CRMソフトウェア.md",
    "chars": 2052,
    "preview": "# IDURAR オープンソース ERP&CRMソフトウェア\n\nGitHub:[https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idurar-erp-c"
  },
  {
    "path": "features/ko_kr_자유_오픈_소스_ERP_CRM_소프트웨어.md",
    "chars": 2224,
    "preview": "# IDURAR 오픈 소스 ERP & CRM 소프트웨어\n\nGitHub : [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idurar-erp"
  },
  {
    "path": "features/lt_lt_nemokamas_atviras_kodo_erp_crm_programinė_įranga.md",
    "chars": 4099,
    "preview": "# IDURAR Atviro kodo ERP ir CRM programinė įranga\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com"
  },
  {
    "path": "features/lv_lv_bezmaksas_atvērtā_koda_erp_crm_programmatūra.md",
    "chars": 4199,
    "preview": "# IDURAR Atvērtā koda ERP un CRM programmatūra\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/id"
  },
  {
    "path": "features/mk_mk_фрее_опен_сорсе_ерп_црм_софтвер.md",
    "chars": 4515,
    "preview": "# IDURAR Open-Source ERP & CRM Софтвер\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idu"
  },
  {
    "path": "features/ms_my_fail_terbuka_sumber_erp_crm_perisian.md",
    "chars": 4321,
    "preview": "# Perisian Sumber Terbuka IDURAR ERP & CRM\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar"
  },
  {
    "path": "features/nb_no_gratis_åpen_kilde_erp_crm_programvare.md",
    "chars": 3915,
    "preview": "# IDURAR Åpen kildekode ERP og CRM-programvare\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/id"
  },
  {
    "path": "features/nl_nl_vrije_open_source_erp_crm_software.md",
    "chars": 4258,
    "preview": "# IDURAR Open-Source ERP & CRM Software\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/pl_pl_bezpłatne_otwarte_źródło_erp_crm_oprogramowanie.md",
    "chars": 4344,
    "preview": "# Oprogramowanie IDURAR Open-Source ERP & CRM\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idu"
  },
  {
    "path": "features/pt_br_software_de_erp_e_crm_de_código_aberto_gratuito.md",
    "chars": 4451,
    "preview": "# IDURAR Software ERP & CRM de código aberto\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idur"
  },
  {
    "path": "features/pt_pt_software_de_erp_crm_de_código_aberto_gratuito.md",
    "chars": 4353,
    "preview": "# IDURAR Software ERP e CRM de código aberto\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idur"
  },
  {
    "path": "features/ro_ro_software_erp_crm_open_source_gratuit.md",
    "chars": 4617,
    "preview": "# IDURAR Software ERP și CRM Open-Source\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/i"
  },
  {
    "path": "features/ru_ru_бесплатное_открытое_программное_обеспечение_erp_crm.md",
    "chars": 4468,
    "preview": "# IDURAR Открытое ERP и CRM программное обеспечение\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.c"
  },
  {
    "path": "features/sk_sk_zdarma_otvorene_zdrojove_erp_crm_software.md",
    "chars": 4139,
    "preview": "# IDURAR Open-Source ERP & CRM Software\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/sl_si_brezplačni_odprtokodni_erp_crm_programski_oprema.md",
    "chars": 4279,
    "preview": "# IDURAR Odprtokodna ERP in CRM programska oprema\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com"
  },
  {
    "path": "features/sr_rs_besplatni_otvoreni_izvor_erp_crm_softver.md",
    "chars": 4280,
    "preview": "# IDURAR Open-Source ERP & CRM Softver\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idu"
  },
  {
    "path": "features/sv_se_fri_öppen_källkods_erp_crm_programvara.md",
    "chars": 4094,
    "preview": "# IDURAR Öppen källkod ERP & CRM-programvara\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idur"
  },
  {
    "path": "features/th_th_ฟรี_โปรแกรม_ตัวจัดการแหล่งข้อมูลโปรแกรม_ERP_CRM.md",
    "chars": 3408,
    "preview": "# ซอฟต์แวร์ ERP & CRM โอเพ่นซอร์ส IDURAR\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/i"
  },
  {
    "path": "features/tr_tr_ücretsiz_açık_kaynak_erp_crm_yazılımı.md",
    "chars": 4277,
    "preview": "# IDURAR Açık Kaynaklı ERP ve CRM Yazılımı\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar"
  },
  {
    "path": "features/uk_ua_безкоштовне_відкрите_джерело_erp_crm_програмне_забезпечення.md",
    "chars": 4402,
    "preview": "# IDURAR Відкритий ERP та CRM-софт\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idurar-"
  },
  {
    "path": "features/ur_pk_مفت_کھولیں_سورس_erp_crm_سافٹ ویئر.md",
    "chars": 3909,
    "preview": "# IDURAR اوپن سورس ERP & CRM سافٹ ویئر\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idu"
  },
  {
    "path": "features/vi_vn_chương_trình_quản_lý_doanh_nghiệp_crm_nguồn_mở_miễn_phí.md",
    "chars": 3907,
    "preview": "# IDURAR Phần mềm ERP & CRM mã nguồn mở\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/id"
  },
  {
    "path": "features/zh_cn_免费开源ERP CRM软件.md",
    "chars": 1491,
    "preview": "# IDURAR 开源 ERP & CRM 软件\n\nGitHub: [https://github.com/idurar/idurar-erp-crm](https://github.com/idurar/idurar-erp-crm)\n演"
  },
  {
    "path": "frontend/.eslintrc.js",
    "chars": 535,
    "preview": "module.exports = {\n  root: true,\n  env: { browser: true, es2020: true },\n  extends: [\n    'eslint:recommended',\n    'plu"
  },
  {
    "path": "frontend/.gitignore",
    "chars": 334,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\r\n\r\n# dependencies\r\n/node_modules\r\n"
  },
  {
    "path": "frontend/.prettierignore",
    "chars": 54,
    "preview": "# Ignore artifacts:\nbuild\ncoverage\nnode_modules\npublic"
  },
  {
    "path": "frontend/.prettierrc",
    "chars": 106,
    "preview": "{\n  \"printWidth\": 100,\n  \"trailingComma\": \"es5\",\n  \"tabWidth\": 2,\n  \"semi\": true,\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": "frontend/.vscode/settings.json",
    "chars": 407,
    "preview": "{\n  \"editor.formatOnPaste\": true,\n  \"editor.formatOnSave\": true,\n  \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n"
  },
  {
    "path": "frontend/README.md",
    "chars": 2870,
    "preview": "This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\n## Available Scrip"
  },
  {
    "path": "frontend/index.html",
    "chars": 583,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "frontend/jsconfig.json",
    "chars": 134,
    "preview": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \"src\",\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    }\n  },\n  \"exclude\": [\"node_module"
  },
  {
    "path": "frontend/package.json",
    "chars": 1227,
    "preview": "{\n  \"name\": \"idurar-erp-crm\",\n  \"version\": \"4.1.0\",\n  \"engines\": {\n    \"node\": \"20.9.0\",\n    \"npm\": \"10.2.4\"\n  },\n  \"typ"
  },
  {
    "path": "frontend/public/robots.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "frontend/rollup.config.js",
    "chars": 266,
    "preview": "import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';\n\n// function importModule(path) {\n//   // who knows "
  },
  {
    "path": "frontend/src/RootApp.jsx",
    "chars": 532,
    "preview": "import './style/app.css';\n\nimport { Suspense, lazy } from 'react';\nimport { BrowserRouter } from 'react-router-dom';\nimp"
  },
  {
    "path": "frontend/src/apps/ErpApp.jsx",
    "chars": 2505,
    "preview": "import { useLayoutEffect } from 'react';\nimport { useEffect } from 'react';\nimport { selectAppSettings } from '@/redux/s"
  },
  {
    "path": "frontend/src/apps/Header/HeaderContainer.jsx",
    "chars": 3503,
    "preview": "import { useSelector } from 'react-redux';\nimport { Link, useNavigate } from 'react-router-dom';\nimport { Avatar, Dropdo"
  },
  {
    "path": "frontend/src/apps/Header/UpgradeButton.jsx",
    "chars": 978,
    "preview": "import { Avatar, Popover, Button, Badge, Col, List } from 'antd';\n\n// import Notifications from '@/components/Notificati"
  },
  {
    "path": "frontend/src/apps/IdurarOs.jsx",
    "chars": 2240,
    "preview": "import { lazy, Suspense, useEffect, useState } from 'react';\n\nimport { useSelector } from 'react-redux';\nimport { select"
  },
  {
    "path": "frontend/src/apps/Navigation/NavigationContainer.jsx",
    "chars": 5183,
    "preview": "import { useState, useEffect } from 'react';\nimport { Link, useLocation, useNavigate } from 'react-router-dom';\nimport {"
  },
  {
    "path": "frontend/src/auth/auth.service.js",
    "chars": 2464,
    "preview": "import { API_BASE_URL } from '@/config/serverApiConfig';\n\nimport axios from 'axios';\nimport errorHandler from '@/request"
  },
  {
    "path": "frontend/src/auth/index.js",
    "chars": 32,
    "preview": "export * from './auth.service';\n"
  },
  {
    "path": "frontend/src/components/AutoCompleteAsync/index.jsx",
    "chars": 3921,
    "preview": "import { useState, useEffect, useRef } from 'react';\n\nimport { request } from '@/request';\nimport useOnFetch from '@/hoo"
  },
  {
    "path": "frontend/src/components/CollapseBox/index.jsx",
    "chars": 1402,
    "preview": "import React from 'react';\nimport { Row, Col } from 'antd';\n\nconst CollapseBoxButton = ({ onChange, title }) => {\n  retu"
  },
  {
    "path": "frontend/src/components/CreateForm/index.jsx",
    "chars": 1837,
    "preview": "import { useEffect } from 'react';\n\nimport { useDispatch, useSelector } from 'react-redux';\nimport { crud } from '@/redu"
  }
]

// ... and 229 more files (download for full content)

About this extraction

This page contains the full source code of the idurar/idurar-erp-crm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 429 files (851.9 KB), approximately 240.2k tokens, and a symbol index with 270 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!