From 74b4b2df4ee184b54a2b3c84487d7d88d78d6aab Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski Date: Mon, 6 Apr 2026 17:59:15 +0200 Subject: [PATCH] Finalize Typescript restructure --- .../Controllers/Admin/BackupsController.php | 1 - app/Models/User.php | 6 + .../Backup/BackupConfigurationFactory.php | 13 +- config/invoiceshelf.php | 21 +- lang/en.json | 15 +- resources/scripts-v2/api/index.ts | 12 +- .../scripts-v2/api/services/auth.service.ts | 9 +- .../scripts-v2/api/services/backup.service.ts | 31 +- .../api/services/bootstrap.service.ts | 4 +- .../api/services/custom-field.service.ts | 1 + .../api/services/customer.service.ts | 37 +- .../scripts-v2/api/services/disk.service.ts | 49 +- resources/scripts-v2/api/services/index.ts | 14 +- .../api/services/invoice.service.ts | 16 +- .../scripts-v2/api/services/mail.service.ts | 7 +- .../scripts-v2/api/services/member.service.ts | 2 +- .../scripts-v2/api/services/pdf.service.ts | 5 +- .../api/services/setting.service.ts | 4 +- .../scripts-v2/api/services/update.service.ts | 74 + .../scripts-v2/components/base/BaseCard.vue | 2 +- .../components/base/BaseCustomInput.vue | 2 +- .../base/BaseCustomerSelectPopup.vue | 145 +- .../scripts-v2/components/base/BaseDialog.vue | 12 +- .../components/base/BaseDropdown.vue | 60 +- .../components/base/BaseItemSelect.vue | 55 +- .../scripts-v2/components/base/BaseModal.vue | 10 +- .../components/base/BaseMultiselect.vue | 1383 +++++++++++++++-- .../components/base/BasePdfPreview.vue | 79 + .../scripts-v2/components/base/BaseTab.vue | 24 + .../components/base/BaseTabGroup.vue | 6 +- .../components/base/EstimateStatusBadge.vue | 16 +- .../components/base/InvoicePublicPage.vue | 28 +- .../components/base/InvoiceStatusBadge.vue | 22 +- .../components/base/PaidStatusBadge.vue | 16 +- .../base/RecurringInvoiceStatusBadge.vue | 18 +- resources/scripts-v2/components/base/index.ts | 2 + .../components/layout/FilterWrapper.vue | 42 +- .../notifications/NotificationItem.vue | 6 +- .../scripts-v2/components/table/DataTable.vue | 4 +- .../scripts-v2/composables/use-company.ts | 6 +- .../components/settings/AdminBackupModal.vue | 270 ++++ .../settings/AdminFileDiskModal.vue | 565 +++++++ .../components/settings/AdminPdfDomDriver.vue | 105 ++ .../settings/AdminPdfGotenbergDriver.vue | 180 +++ resources/scripts-v2/features/admin/routes.ts | 21 +- .../admin/views/settings/AdminBackupView.vue | 328 ++++ .../views/settings/AdminFileDiskView.vue | 295 ++++ .../views/settings/AdminMailConfigView.vue | 127 ++ .../views/settings/AdminPdfGenerationView.vue | 96 ++ .../views/settings/AdminUpdateAppView.vue | 481 ++++++ resources/scripts-v2/features/auth/routes.ts | 18 +- .../auth/views/ForgotPasswordView.vue | 6 +- .../features/auth/views/LoginView.vue | 8 +- .../auth/views/RegisterWithInvitationView.vue | 264 ++-- .../features/auth/views/ResetPasswordView.vue | 6 +- .../components/CreateCustomFields.vue | 46 +- .../customers/components/CustomerChart.vue | 45 +- .../customers/components/CustomerDropdown.vue | 63 +- .../customers/components/CustomerModal.vue | 13 +- .../components/types/DateTimeType.vue | 15 + .../customers/components/types/DateType.vue | 15 + .../components/types/DropdownType.vue | 29 + .../customers/components/types/InputType.vue | 15 + .../customers/components/types/NumberType.vue | 15 + .../customers/components/types/PhoneType.vue | 15 + .../customers/components/types/SwitchType.vue | 15 + .../components/types/TextAreaType.vue | 15 + .../customers/components/types/TimeType.vue | 15 + .../customers/components/types/UrlType.vue | 15 + .../features/company/customers/routes.ts | 4 + .../features/company/customers/store.ts | 16 +- .../customers/views/CustomerCreateView.vue | 12 +- .../customers/views/CustomerDetailView.vue | 6 +- .../dashboard/components/DashboardTable.vue | 45 +- .../features/company/dashboard/routes.ts | 1 + .../company/dashboard/views/DashboardView.vue | 4 +- .../components/EstimateBasicFields.vue | 5 +- .../estimates/components/EstimateDropdown.vue | 155 +- .../components/SendEstimateModal.vue | 321 ++++ .../features/company/estimates/routes.ts | 4 + .../features/company/estimates/store.ts | 32 +- .../estimates/views/EstimateCreateView.vue | 16 +- .../estimates/views/EstimateDetailView.vue | 88 +- .../estimates/views/EstimateIndexView.vue | 82 +- .../components/ExpenseCategoryDropdown.vue | 52 +- .../expenses/components/ExpenseDropdown.vue | 29 +- .../features/company/expenses/routes.ts | 3 + .../expenses/views/ExpenseIndexView.vue | 62 +- .../components/InvoiceBasicFields.vue | 15 +- .../invoices/components/InvoiceDropdown.vue | 91 +- .../invoices/components/RecurringFields.vue | 234 +++ .../invoices/components/SendInvoiceModal.vue | 378 +++++ .../features/company/invoices/routes.ts | 4 + .../features/company/invoices/store.ts | 34 +- .../invoices/views/InvoiceCreateView.vue | 249 ++- .../invoices/views/InvoiceDetailView.vue | 90 +- .../invoices/views/InvoiceIndexView.vue | 850 ++++++++-- .../company/items/components/ItemModal.vue | 52 +- .../features/company/items/routes.ts | 3 + .../features/company/items/use-tax-types.ts | 28 + .../company/items/views/ItemCreateView.vue | 17 +- .../members/components/InviteMemberModal.vue | 2 +- .../features/company/members/routes.ts | 3 +- .../company/members/views/MemberIndexView.vue | 32 +- .../features/company/modules/routes.ts | 2 + .../modules/views/ModuleDetailView.vue | 32 +- .../company/modules/views/ModuleIndexView.vue | 2 +- .../payments/components/PaymentDropdown.vue | 36 +- .../payments/components/SendPaymentModal.vue | 321 ++++ .../features/company/payments/routes.ts | 5 + .../features/company/payments/store.ts | 19 +- .../payments/views/PaymentCreateView.vue | 108 +- .../payments/views/PaymentDetailView.vue | 47 +- .../payments/views/PaymentIndexView.vue | 81 +- .../RecurringInvoiceBasicFields.vue | 3 +- .../components/RecurringInvoiceDropdown.vue | 45 +- .../company/recurring-invoices/routes.ts | 23 +- .../company/recurring-invoices/store.ts | 97 +- .../views/RecurringInvoiceCreateView.vue | 3 +- .../views/RecurringInvoiceDetailView.vue | 530 ++++++- .../views/RecurringInvoiceIndexView.vue | 67 +- .../features/company/reports/routes.ts | 33 +- .../reports/views/ExpensesReportView.vue | 9 +- .../reports/views/ProfitLossReportView.vue | 9 +- .../reports/views/ReportsLayoutView.vue | 72 + .../company/reports/views/SalesReportView.vue | 9 +- .../company/reports/views/TaxReportView.vue | 9 +- .../settings/components/CategoryModal.vue | 10 + .../settings/components/CompanyModal.vue | 260 ++++ .../settings/components/CustomFieldModal.vue | 45 + .../components/DeleteCompanyModal.vue | 139 ++ .../settings/components/EstimatesTab.vue | 13 +- .../EstimatesTabConvertEstimate.vue | 67 + .../components/EstimatesTabDefaultFormats.vue | 120 ++ .../components/EstimatesTabExpiryDate.vue | 139 ++ .../components/ExchangeRateProviderModal.vue | 10 + .../components/ExpenseCategoryDropdown.vue | 8 +- .../settings/components/InvoicesTab.vue | 19 +- .../components/InvoicesTabDefaultFormats.vue | 117 ++ .../components/InvoicesTabDueDate.vue | 134 ++ .../components/InvoicesTabRetrospective.vue | 59 + .../settings/components/ItemUnitModal.vue | 23 +- .../settings/components/MailTestModal.vue | 15 +- .../settings/components/NoteDropdown.vue | 13 +- .../settings/components/NumberCustomizer.vue | 4 +- .../components/PaymentModeDropdown.vue | 2 +- .../settings/components/PaymentModeModal.vue | 10 + .../settings/components/PaymentsTab.vue | 7 +- .../components/PaymentsTabDefaultFormats.vue | 107 ++ .../settings/components/RoleDropdown.vue | 12 +- .../settings/components/RolesModal.vue | 67 +- .../settings/components/TaxTypeDropdown.vue | 8 +- .../settings/components/TaxTypeModal.vue | 10 + .../features/company/settings/routes.ts | 164 +- .../settings/views/AccountSettingsView.vue | 24 +- .../settings/views/CompanyInfoView.vue | 26 - .../settings/views/CustomizationView.vue | 11 + .../company/settings/views/DangerZoneView.vue | 40 + .../company/settings/views/NotesView.vue | 5 +- .../settings/views/PreferencesView.vue | 22 +- .../company/settings/views/RolesView.vue | 10 +- .../settings/views/SettingsLayoutView.vue | 46 +- .../settings/views/UserGeneralView.vue | 98 ++ .../settings/views/UserProfilePhotoView.vue | 79 + .../settings/views/UserSecurityView.vue | 96 ++ .../settings/views/UserSettingsLayoutView.vue | 107 ++ .../components/CustomerPortalAuthLayout.vue | 84 + .../components/CustomerPortalHeader.vue | 166 ++ .../components/CustomerPortalLayout.vue | 41 +- .../features/customer-portal/routes.ts | 34 +- .../features/customer-portal/store.ts | 143 +- .../features/customer-portal/utils/routes.ts | 41 + .../views/CustomerEstimateDetailView.vue | 66 +- .../views/CustomerInvoiceDetailView.vue | 8 +- .../views/CustomerPaymentDetailView.vue | 8 +- .../views/CustomerSettingsView.vue | 197 +-- .../auth/CustomerPortalForgotPasswordView.vue | 116 ++ .../views/auth/CustomerPortalLoginView.vue | 158 ++ .../auth/CustomerPortalResetPasswordView.vue | 199 +++ .../installation/views/PreferencesView.vue | 61 +- .../shared/document-form/DocumentItemRow.vue | 3 +- .../document-form/DocumentItemRowTax.vue | 8 +- .../document-form/DocumentItemsTable.vue | 2 +- .../shared/document-form/DocumentTotals.vue | 3 +- .../document-form/ExchangeRateConverter.vue | 23 +- .../shared/document-form/NoteSelectPopup.vue | 29 +- .../document-form/SelectTemplateModal.vue | 164 ++ .../shared/document-form/TaxSelectPopup.vue | 7 +- .../document-form/TemplateSelectButton.vue | 7 +- .../features/shared/document-form/index.ts | 1 + .../scripts-v2/layouts/CompanyLayout.vue | 70 +- .../layouts/partials/CompanySwitcher.vue | 3 + .../layouts/partials/SiteHeader.vue | 2 +- resources/scripts-v2/main.ts | 1 + resources/scripts-v2/router/guards.ts | 66 + resources/scripts-v2/router/types.ts | 5 +- resources/scripts-v2/stores/company.store.ts | 4 +- resources/scripts-v2/stores/global.store.ts | 25 +- resources/scripts-v2/stores/modal.store.ts | 4 +- resources/scripts-v2/utils/error-handling.ts | 1 + .../scripts-v2/utils/generate-client-id.ts | 5 + resources/scripts-v2/utils/index.ts | 2 + resources/scripts-v2/utils/local-storage.ts | 20 + resources/views/app.blade.php | 5 + tests/Feature/Admin/AdminSettingsTest.php | 136 ++ tests/Feature/Admin/BackupGlobalTest.php | 48 + tests/Feature/Admin/CustomerTest.php | 26 +- tests/Feature/Customer/AuthTest.php | 83 + version.md | 2 +- 209 files changed, 12419 insertions(+), 1745 deletions(-) create mode 100644 resources/scripts-v2/api/services/update.service.ts create mode 100644 resources/scripts-v2/components/base/BasePdfPreview.vue create mode 100644 resources/scripts-v2/components/base/BaseTab.vue create mode 100644 resources/scripts-v2/features/admin/components/settings/AdminBackupModal.vue create mode 100644 resources/scripts-v2/features/admin/components/settings/AdminFileDiskModal.vue create mode 100644 resources/scripts-v2/features/admin/components/settings/AdminPdfDomDriver.vue create mode 100644 resources/scripts-v2/features/admin/components/settings/AdminPdfGotenbergDriver.vue create mode 100644 resources/scripts-v2/features/admin/views/settings/AdminBackupView.vue create mode 100644 resources/scripts-v2/features/admin/views/settings/AdminFileDiskView.vue create mode 100644 resources/scripts-v2/features/admin/views/settings/AdminMailConfigView.vue create mode 100644 resources/scripts-v2/features/admin/views/settings/AdminPdfGenerationView.vue create mode 100644 resources/scripts-v2/features/admin/views/settings/AdminUpdateAppView.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/DateTimeType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/DateType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/DropdownType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/InputType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/NumberType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/PhoneType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/SwitchType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/TextAreaType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/TimeType.vue create mode 100644 resources/scripts-v2/features/company/customers/components/types/UrlType.vue create mode 100644 resources/scripts-v2/features/company/estimates/components/SendEstimateModal.vue create mode 100644 resources/scripts-v2/features/company/invoices/components/RecurringFields.vue create mode 100644 resources/scripts-v2/features/company/invoices/components/SendInvoiceModal.vue create mode 100644 resources/scripts-v2/features/company/items/use-tax-types.ts create mode 100644 resources/scripts-v2/features/company/payments/components/SendPaymentModal.vue create mode 100644 resources/scripts-v2/features/company/reports/views/ReportsLayoutView.vue create mode 100644 resources/scripts-v2/features/company/settings/components/CompanyModal.vue create mode 100644 resources/scripts-v2/features/company/settings/components/DeleteCompanyModal.vue create mode 100644 resources/scripts-v2/features/company/settings/components/EstimatesTabConvertEstimate.vue create mode 100644 resources/scripts-v2/features/company/settings/components/EstimatesTabDefaultFormats.vue create mode 100644 resources/scripts-v2/features/company/settings/components/EstimatesTabExpiryDate.vue create mode 100644 resources/scripts-v2/features/company/settings/components/InvoicesTabDefaultFormats.vue create mode 100644 resources/scripts-v2/features/company/settings/components/InvoicesTabDueDate.vue create mode 100644 resources/scripts-v2/features/company/settings/components/InvoicesTabRetrospective.vue create mode 100644 resources/scripts-v2/features/company/settings/components/PaymentsTabDefaultFormats.vue create mode 100644 resources/scripts-v2/features/company/settings/views/DangerZoneView.vue create mode 100644 resources/scripts-v2/features/company/settings/views/UserGeneralView.vue create mode 100644 resources/scripts-v2/features/company/settings/views/UserProfilePhotoView.vue create mode 100644 resources/scripts-v2/features/company/settings/views/UserSecurityView.vue create mode 100644 resources/scripts-v2/features/company/settings/views/UserSettingsLayoutView.vue create mode 100644 resources/scripts-v2/features/customer-portal/components/CustomerPortalAuthLayout.vue create mode 100644 resources/scripts-v2/features/customer-portal/components/CustomerPortalHeader.vue create mode 100644 resources/scripts-v2/features/customer-portal/utils/routes.ts create mode 100644 resources/scripts-v2/features/customer-portal/views/auth/CustomerPortalForgotPasswordView.vue create mode 100644 resources/scripts-v2/features/customer-portal/views/auth/CustomerPortalLoginView.vue create mode 100644 resources/scripts-v2/features/customer-portal/views/auth/CustomerPortalResetPasswordView.vue create mode 100644 resources/scripts-v2/features/shared/document-form/SelectTemplateModal.vue create mode 100644 resources/scripts-v2/utils/generate-client-id.ts create mode 100644 tests/Feature/Admin/AdminSettingsTest.php create mode 100644 tests/Feature/Admin/BackupGlobalTest.php create mode 100644 tests/Feature/Customer/AuthTest.php diff --git a/app/Http/Controllers/Admin/BackupsController.php b/app/Http/Controllers/Admin/BackupsController.php index 099bffeb..7b27234b 100644 --- a/app/Http/Controllers/Admin/BackupsController.php +++ b/app/Http/Controllers/Admin/BackupsController.php @@ -68,7 +68,6 @@ class BackupsController extends Controller $this->authorize('manage backups'); $data = $request->all(); - $data['company'] = $request->header('company'); dispatch(new CreateBackupJob($data))->onQueue(config('backup.queue.name')); diff --git a/app/Models/User.php b/app/Models/User.php index 8a5b8220..898a5264 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -257,6 +257,12 @@ class User extends Authenticatable implements HasMedia $query->wherePhone($filters->get('phone')); } + if ($filters->get('role')) { + $query->whereHas('roles', function ($q) use ($filters) { + $q->where('roles.id', $filters->get('role')); + }); + } + if ($filters->get('orderByField') || $filters->get('orderBy')) { $field = $filters->get('orderByField') ? $filters->get('orderByField') : 'name'; $orderBy = $filters->get('orderBy') ? $filters->get('orderBy') : 'asc'; diff --git a/app/Services/Backup/BackupConfigurationFactory.php b/app/Services/Backup/BackupConfigurationFactory.php index cb5f258a..e2fd9acd 100644 --- a/app/Services/Backup/BackupConfigurationFactory.php +++ b/app/Services/Backup/BackupConfigurationFactory.php @@ -2,19 +2,14 @@ namespace App\Services\Backup; -use App\Models\CompanySetting; use App\Models\FileDisk; use Exception; use Spatie\Backup\Config\Config; class BackupConfigurationFactory { - public static function make($data = []): Config + public static function make(array $data = []): Config { - if (blank($data['company'] ?? null)) { - throw new Exception('The Company ID is missig'); - } - if (blank($data['file_disk_id'] ?? null)) { throw new Exception('No file disk selected'); } @@ -27,12 +22,6 @@ class BackupConfigurationFactory config(['backup.backup.destination.disks' => [$prefix.$fileDisk->driver]]); - $companyNotificationEmail = CompanySetting::getSetting('notification_email', $data['company']); - - if ($companyNotificationEmail) { - config(['backup.notifications.mail.to' => $companyNotificationEmail]); - } - $config = Config::fromArray(config('backup')); return $config; diff --git a/config/invoiceshelf.php b/config/invoiceshelf.php index d8515cfb..e3ee9a5c 100644 --- a/config/invoiceshelf.php +++ b/config/invoiceshelf.php @@ -9,7 +9,6 @@ use App\Models\Invoice; use App\Models\Item; use App\Models\Note; use App\Models\Payment; -use App\Models\RecurringInvoice; use App\Models\TaxType; return [ @@ -164,7 +163,7 @@ return [ 'title' => 'settings.roles.title', 'group' => '', 'name' => 'Company Roles', - 'link' => '/admin/settings/roles-settings', + 'link' => '/admin/settings/roles', 'icon' => 'UserGroupIcon', 'owner_only' => true, 'ability' => '', @@ -174,7 +173,7 @@ return [ 'title' => 'settings.menu_title.exchange_rate', 'group' => '', 'name' => 'Exchange Rate Provider', - 'link' => '/admin/settings/exchange-rate-provider', + 'link' => '/admin/settings/exchange-rate', 'icon' => 'BanknotesIcon', 'owner_only' => false, 'ability' => 'view-exchange-rate-provider', @@ -204,7 +203,7 @@ return [ 'title' => 'settings.menu_title.payment_modes', 'group' => '', 'name' => 'Payment modes', - 'link' => '/admin/settings/payment-mode', + 'link' => '/admin/settings/payment-modes', 'icon' => 'CreditCardIcon', 'owner_only' => false, 'ability' => 'view-payment', @@ -234,7 +233,7 @@ return [ 'title' => 'settings.menu_title.expense_category', 'group' => '', 'name' => 'Expense Category', - 'link' => '/admin/settings/expense-category', + 'link' => '/admin/settings/expense-categories', 'icon' => 'ClipboardDocumentListIcon', 'owner_only' => false, 'ability' => 'view-expense', @@ -244,7 +243,7 @@ return [ 'title' => 'settings.mail.company_mail_config', 'group' => '', 'name' => 'Mail Configuration', - 'link' => '/admin/settings/mail-configuration', + 'link' => '/admin/settings/mail-config', 'icon' => 'EnvelopeIcon', 'owner_only' => true, 'ability' => '', @@ -306,16 +305,6 @@ return [ 'ability' => 'view-invoice', 'model' => Invoice::class, ], - [ - 'title' => 'navigation.recurring-invoices', - 'group' => 2, - 'link' => '/admin/recurring-invoices', - 'icon' => 'DocumentTextIcon', - 'name' => 'Recurring Invoices', - 'owner_only' => false, - 'ability' => 'view-recurring-invoice', - 'model' => RecurringInvoice::class, - ], [ 'title' => 'navigation.payments', 'group' => 2, diff --git a/lang/en.json b/lang/en.json index d85f1036..211dd8f2 100644 --- a/lang/en.json +++ b/lang/en.json @@ -102,6 +102,7 @@ "street_2": "Street 2", "action_failed": "Action Failed", "retry": "Retry", + "unable_to_load_pdf": "Unable to load document preview", "choose_note": "Choose Note", "no_note_found": "No Note Found", "insert_note": "Insert Note", @@ -451,6 +452,7 @@ "update_expense": "Update Expense", "edit_invoice": "Edit Invoice", "new_invoice": "New Invoice", + "one_time": "One-time", "save_invoice": "Save Invoice", "update_invoice": "Update Invoice", "add_new_tax": "Add New Tax", @@ -550,6 +552,7 @@ "update_expense": "Update Expense", "edit_invoice": "Edit Recurring Invoice", "new_invoice": "New Recurring Invoice", + "recurring": "Recurring", "send_automatically": "Send Automatically", "send_automatically_desc": "Enable this, if you would like to send the invoice automatically to the customer when its created.", "save_invoice": "Save Recurring Invoice", @@ -594,7 +597,13 @@ "every_hour": "Every Hour", "every_2_hour": "Every 2 Hour", "every_day_at_midnight": "Every day at midnight", + "every_day": "Every Day", "every_week": "Every Week", + "every_2_weeks": "Every 2 Weeks", + "every_month": "Every Month", + "every_2_months": "Every 2 Months", + "every_quarter": "Every 3 Months (Quarterly)", + "every_year": "Every Year", "every_15_days_at_midnight": "Every 15 days at midnight", "on_the_first_day_of_every_month_at_midnight": "On the first day of every month at 00:00", "every_6_month": "Every 6 Month", @@ -613,7 +622,8 @@ "none": "None", "date": "Date", "count": "Count" - } + }, + "make_recurring": "Make Recurring" }, "payments": { "title": "Payments", @@ -771,6 +781,7 @@ "date_of_creation": "Date Of Creation", "action": "Action", "invite_member": "Invite Member", + "select_role": "Select Role", "add_member": "Add Member", "save_member": "Save Member", "update_member": "Update Member", @@ -968,6 +979,7 @@ "updated_message": "Company information updated successfully", "delete_company": "Delete Company", "delete_company_description": "Once you delete your company, you will lose all the data and files associated with it permanently.", + "danger_zone": "Danger Zone", "are_you_absolutely_sure": "Are you absolutely sure?", "delete_company_modal_desc": "This action cannot be undone. This will permanently delete {company} and all of its associated data.", "delete_company_modal_label": "Please type {company} to confirm" @@ -1188,6 +1200,7 @@ "description": "Manage the roles & permissions of this company", "save": "Save", "add_new_role": "Add New Role", + "system_role": "System Role", "role_name": "Role Name", "added_on": "Added on", "add_role": "Add Role", diff --git a/resources/scripts-v2/api/index.ts b/resources/scripts-v2/api/index.ts index b3937745..7d5a4abc 100644 --- a/resources/scripts-v2/api/index.ts +++ b/resources/scripts-v2/api/index.ts @@ -27,6 +27,7 @@ export { mailService, pdfService, diskService, + updateService, } from './services' // Re-export all service types @@ -55,7 +56,9 @@ export type { FrequencyDateResponse, CustomerListParams, CustomerListResponse, - CustomerStatsData, + CustomerStatsChartData, + CustomerStatsParams, + CustomerStatsResponse, PaymentListParams, PaymentListResponse, SendPaymentPayload, @@ -103,6 +106,7 @@ export type { ModuleInstallPayload, ModuleCheckResponse, Backup, + BackupListResponse, CreateBackupPayload, DeleteBackupParams, MailConfig, @@ -119,5 +123,11 @@ export type { GotenbergConfig, Disk, DiskDriversResponse, + DiskDriverValue, CreateDiskPayload, + CheckUpdateResponse, + UpdateRelease, + UpdateDownloadResponse, + UpdateStepResponse, + FinishUpdatePayload, } from './services' diff --git a/resources/scripts-v2/api/services/auth.service.ts b/resources/scripts-v2/api/services/auth.service.ts index eb5694c5..eb68a21f 100644 --- a/resources/scripts-v2/api/services/auth.service.ts +++ b/resources/scripts-v2/api/services/auth.service.ts @@ -36,6 +36,11 @@ export interface RegisterWithInvitationPayload { email: string password: string password_confirmation: string + invitation_token: string +} + +export interface RegisterWithInvitationResponse { + type: string token: string } @@ -74,8 +79,8 @@ export const authService = { return data }, - async registerWithInvitation(payload: RegisterWithInvitationPayload): Promise> { - const { data } = await client.post(API.REGISTER_WITH_INVITATION, payload) + async registerWithInvitation(payload: RegisterWithInvitationPayload): Promise { + const { data } = await client.post(API.REGISTER_WITH_INVITATION, payload) return data }, } diff --git a/resources/scripts-v2/api/services/backup.service.ts b/resources/scripts-v2/api/services/backup.service.ts index d6f86922..7c417454 100644 --- a/resources/scripts-v2/api/services/backup.service.ts +++ b/resources/scripts-v2/api/services/backup.service.ts @@ -1,28 +1,35 @@ import { client } from '../client' import { API } from '../endpoints' -import type { ApiResponse, ListParams } from '@v2/types/api' export interface Backup { - id: number - disk: string path: string created_at: string - file_size: string + size: string +} + +export interface BackupListResponse { + backups: Backup[] + disks: string[] + error?: string + error_message?: string } export interface CreateBackupPayload { - option: 'full' | 'database' | 'files' - selected_disk: string | null + option: 'full' | 'only-db' | 'only-files' + file_disk_id: number } export interface DeleteBackupParams { disk: string - path?: string - file_name?: string + path: string + file_disk_id?: number } export const backupService = { - async list(params?: ListParams): Promise> { + async list(params: { + disk: string + file_disk_id?: number + }): Promise { const { data } = await client.get(API.BACKUPS, { params }) return data }, @@ -37,7 +44,11 @@ export const backupService = { return data }, - async download(params: { disk: string; path?: string; file_name?: string }): Promise { + async download(params: { + disk: string + path: string + file_disk_id?: number + }): Promise { const { data } = await client.get(API.DOWNLOAD_BACKUP, { params, responseType: 'blob', diff --git a/resources/scripts-v2/api/services/bootstrap.service.ts b/resources/scripts-v2/api/services/bootstrap.service.ts index d8c799ff..c9a241b3 100644 --- a/resources/scripts-v2/api/services/bootstrap.service.ts +++ b/resources/scripts-v2/api/services/bootstrap.service.ts @@ -8,9 +8,10 @@ import type { Ability } from '@v2/types/domain/role' export interface MenuItem { title: string name: string - route: string + link: string icon: string group: string + group_label?: string ability?: string } @@ -27,6 +28,7 @@ export interface BootstrapResponse { config: Record global_settings: Record modules: string[] + admin_mode?: boolean pending_invitations?: Array<{ token: string company_name: string diff --git a/resources/scripts-v2/api/services/custom-field.service.ts b/resources/scripts-v2/api/services/custom-field.service.ts index 2c3b95ac..b7a224f4 100644 --- a/resources/scripts-v2/api/services/custom-field.service.ts +++ b/resources/scripts-v2/api/services/custom-field.service.ts @@ -17,6 +17,7 @@ export interface CreateCustomFieldPayload { is_required?: boolean options?: Array<{ name: string }> | string[] | null order?: number | null + default_answer?: string | null } export const customFieldService = { diff --git a/resources/scripts-v2/api/services/customer.service.ts b/resources/scripts-v2/api/services/customer.service.ts index 89f82eb7..f305fd2a 100644 --- a/resources/scripts-v2/api/services/customer.service.ts +++ b/resources/scripts-v2/api/services/customer.service.ts @@ -24,16 +24,28 @@ export interface CustomerListResponse { meta: CustomerListMeta } -export interface CustomerStatsData { - id: number - name: string - email: string | null - total_invoices: number - total_estimates: number - total_payments: number - total_expenses: number - total_amount_due: number - total_paid: number +export interface CustomerStatsChartData { + salesTotal: number + totalReceipts: number + totalExpenses: number + netProfit: number + expenseTotals: number[] + netProfits: number[] + months: string[] + receiptTotals: number[] + invoiceTotals: number[] +} + +export interface CustomerStatsParams { + previous_year?: boolean + this_year?: boolean +} + +export interface CustomerStatsResponse { + data: Customer + meta: { + chartData: CustomerStatsChartData + } } export const customerService = { @@ -62,7 +74,10 @@ export const customerService = { return data }, - async getStats(id: number, params?: Record): Promise> { + async getStats( + id: number, + params?: CustomerStatsParams + ): Promise { const { data } = await client.get(`${API.CUSTOMER_STATS}/${id}/stats`, { params }) return data }, diff --git a/resources/scripts-v2/api/services/disk.service.ts b/resources/scripts-v2/api/services/disk.service.ts index 78f23937..30f26b1e 100644 --- a/resources/scripts-v2/api/services/disk.service.ts +++ b/resources/scripts-v2/api/services/disk.service.ts @@ -1,54 +1,59 @@ import { client } from '../client' import { API } from '../endpoints' -import type { ApiResponse, ListParams } from '@v2/types/api' +import type { ApiResponse, ListParams, PaginatedResponse } from '@v2/types/api' + +export type DiskDriverValue = + | 'local' + | 's3' + | 's3compat' + | 'doSpaces' + | 'dropbox' export interface Disk { id: number name: string - driver: string + type: string + driver: DiskDriverValue set_as_default: boolean - credentials: Record - created_at: string - updated_at: string + credentials: Record | string | null + company_id?: number | null } export interface DiskDriversResponse { - drivers: string[] - [key: string]: unknown + drivers: Array<{ + name: string + value: DiskDriverValue + }> + default: DiskDriverValue | string } export interface CreateDiskPayload { name: string - selected_driver: string - // S3/S3-compat/DOSpaces fields - key?: string - secret?: string - region?: string - bucket?: string - root?: string - endpoint?: string - // Dropbox fields - token?: string - app?: string + driver: DiskDriverValue + credentials?: Record | string + set_as_default?: boolean } export const diskService = { - async list(params?: ListParams): Promise> { + async list(params?: ListParams): Promise> { const { data } = await client.get(API.DISKS, { params }) return data }, - async get(disk: string): Promise> { + async get(disk: DiskDriverValue): Promise> { const { data } = await client.get(`${API.DISKS}/${disk}`) return data }, - async create(payload: CreateDiskPayload): Promise { + async create(payload: CreateDiskPayload): Promise> { const { data } = await client.post(API.DISKS, payload) return data }, - async update(id: number, payload: Partial): Promise> { + async update( + id: number, + payload: Partial + ): Promise> { const { data } = await client.put(`${API.DISKS}/${id}`, payload) return data }, diff --git a/resources/scripts-v2/api/services/index.ts b/resources/scripts-v2/api/services/index.ts index 8e09e39a..f0338e37 100644 --- a/resources/scripts-v2/api/services/index.ts +++ b/resources/scripts-v2/api/services/index.ts @@ -23,6 +23,7 @@ export { backupService } from './backup.service' export { mailService } from './mail.service' export { pdfService } from './pdf.service' export { diskService } from './disk.service' +export { updateService } from './update.service' // Re-export service types for convenience export type { LoginPayload, LoginResponse, ForgotPasswordPayload, ResetPasswordPayload, RegisterWithInvitationPayload } from './auth.service' @@ -30,7 +31,13 @@ export type { BootstrapResponse, MenuItem, CurrentCompanyResponse } from './boot export type { InvoiceListParams, InvoiceListResponse, SendInvoicePayload, InvoiceStatusPayload, InvoiceTemplatesResponse } from './invoice.service' export type { EstimateListParams, EstimateListResponse, SendEstimatePayload, EstimateStatusPayload, EstimateTemplatesResponse } from './estimate.service' export type { RecurringInvoiceListParams, RecurringInvoiceListResponse, FrequencyDateParams, FrequencyDateResponse } from './recurring-invoice.service' -export type { CustomerListParams, CustomerListResponse, CustomerStatsData } from './customer.service' +export type { + CustomerListParams, + CustomerListResponse, + CustomerStatsChartData, + CustomerStatsParams, + CustomerStatsResponse, +} from './customer.service' export type { PaymentListParams, PaymentListResponse, SendPaymentPayload, CreatePaymentMethodPayload } from './payment.service' export type { ExpenseListParams, ExpenseListResponse, CreateExpenseCategoryPayload } from './expense.service' export type { ItemListParams, ItemListResponse, CreateItemPayload, CreateUnitPayload } from './item.service' @@ -46,7 +53,8 @@ export type { CustomFieldListParams, CreateCustomFieldPayload } from './custom-f export type { CreateNotePayload } from './note.service' export type { CreateExchangeRateProviderPayload, BulkUpdatePayload, ExchangeRateResponse, ActiveProviderResponse } from './exchange-rate.service' export type { Module, ModuleInstallPayload, ModuleCheckResponse } from './module.service' -export type { Backup, CreateBackupPayload, DeleteBackupParams } from './backup.service' +export type { Backup, BackupListResponse, CreateBackupPayload, DeleteBackupParams } from './backup.service' export type { MailConfig, MailConfigResponse, MailDriver, SmtpConfig, MailgunConfig, SesConfig, TestMailPayload } from './mail.service' export type { PdfConfig, PdfConfigResponse, PdfDriver, DomPdfConfig, GotenbergConfig } from './pdf.service' -export type { Disk, DiskDriversResponse, CreateDiskPayload } from './disk.service' +export type { Disk, DiskDriversResponse, DiskDriverValue, CreateDiskPayload } from './disk.service' +export type { CheckUpdateResponse, UpdateRelease, UpdateDownloadResponse, UpdateStepResponse, FinishUpdatePayload } from './update.service' diff --git a/resources/scripts-v2/api/services/invoice.service.ts b/resources/scripts-v2/api/services/invoice.service.ts index e6f73e52..2d86b169 100644 --- a/resources/scripts-v2/api/services/invoice.service.ts +++ b/resources/scripts-v2/api/services/invoice.service.ts @@ -30,10 +30,12 @@ export interface InvoiceListResponse { export interface SendInvoicePayload { id: number - subject?: string - body?: string - from?: string - to?: string + subject?: string | null + body?: string | null + from?: string | null + to?: string | null + cc?: string | null + bcc?: string | null } export interface InvoiceStatusPayload { @@ -43,6 +45,12 @@ export interface InvoiceStatusPayload { export interface SendPreviewParams { id: number + from?: string | null + to?: string | null + cc?: string | null + bcc?: string | null + subject?: string | null + body?: string | null } export interface InvoiceTemplate { diff --git a/resources/scripts-v2/api/services/mail.service.ts b/resources/scripts-v2/api/services/mail.service.ts index 3145bbe5..7f90f0ff 100644 --- a/resources/scripts-v2/api/services/mail.service.ts +++ b/resources/scripts-v2/api/services/mail.service.ts @@ -1,10 +1,7 @@ import { client } from '../client' import { API } from '../endpoints' -export interface MailDriver { - name: string - value: string -} +export type MailDriver = string export interface SmtpConfig { mail_driver: string @@ -46,6 +43,8 @@ export interface MailConfigResponse { export interface TestMailPayload { to: string + subject: string + message: string } export const mailService = { diff --git a/resources/scripts-v2/api/services/member.service.ts b/resources/scripts-v2/api/services/member.service.ts index 1bfdb4ae..a91c83bb 100644 --- a/resources/scripts-v2/api/services/member.service.ts +++ b/resources/scripts-v2/api/services/member.service.ts @@ -31,7 +31,7 @@ export interface UpdateMemberPayload { export interface InviteMemberPayload { email: string - role?: string + role_id: number | null } export interface DeleteMembersPayload { diff --git a/resources/scripts-v2/api/services/pdf.service.ts b/resources/scripts-v2/api/services/pdf.service.ts index 480942b3..c5ac7cc5 100644 --- a/resources/scripts-v2/api/services/pdf.service.ts +++ b/resources/scripts-v2/api/services/pdf.service.ts @@ -1,10 +1,7 @@ import { client } from '../client' import { API } from '../endpoints' -export interface PdfDriver { - name: string - value: string -} +export type PdfDriver = string export interface DomPdfConfig { pdf_driver: string diff --git a/resources/scripts-v2/api/services/setting.service.ts b/resources/scripts-v2/api/services/setting.service.ts index 8c153c5f..4b4411c1 100644 --- a/resources/scripts-v2/api/services/setting.service.ts +++ b/resources/scripts-v2/api/services/setting.service.ts @@ -28,7 +28,7 @@ export interface NumberPlaceholdersParams { } export interface NumberPlaceholder { - description: string + name: string value: string } @@ -102,7 +102,7 @@ export const settingService = { }, // App Version - async getAppVersion(): Promise<{ version: string }> { + async getAppVersion(): Promise<{ version: string; channel: string }> { const { data } = await client.get(API.APP_VERSION) return data }, diff --git a/resources/scripts-v2/api/services/update.service.ts b/resources/scripts-v2/api/services/update.service.ts new file mode 100644 index 00000000..f68aac94 --- /dev/null +++ b/resources/scripts-v2/api/services/update.service.ts @@ -0,0 +1,74 @@ +import { client } from '../client' +import { API } from '../endpoints' + +export interface UpdateRelease { + version: string + description?: string | null + changelog?: string | null + extensions?: Record + min_php_version?: string | null + deleted_files?: string | string[] | null +} + +export interface CheckUpdateResponse { + success?: boolean + release: UpdateRelease | null + is_minor?: boolean +} + +export interface UpdateDownloadResponse { + success: boolean + path?: string | boolean | Record | null +} + +export interface UpdateStepResponse { + success: boolean + path?: string | boolean | Record | null + error?: string | boolean + data?: Record +} + +export interface FinishUpdatePayload { + installed: string + version: string +} + +export const updateService = { + async check(channel: 'stable' | 'insider' = 'stable'): Promise { + const { data } = await client.get(API.CHECK_UPDATE, { + params: { channel }, + }) + + return data + }, + + async download(payload: { version: string }): Promise { + const { data } = await client.post(API.UPDATE_DOWNLOAD, payload) + return data + }, + + async unzip(payload: { path: string }): Promise { + const { data } = await client.post(API.UPDATE_UNZIP, payload) + return data + }, + + async copy(payload: { path: string }): Promise { + const { data } = await client.post(API.UPDATE_COPY, payload) + return data + }, + + async delete(payload: { deleted_files?: string | string[] | null }): Promise { + const { data } = await client.post(API.UPDATE_DELETE, payload) + return data + }, + + async migrate(): Promise { + const { data } = await client.post(API.UPDATE_MIGRATE) + return data + }, + + async finish(payload: FinishUpdatePayload): Promise { + const { data } = await client.post(API.UPDATE_FINISH, payload) + return data + }, +} diff --git a/resources/scripts-v2/components/base/BaseCard.vue b/resources/scripts-v2/components/base/BaseCard.vue index f27969da..d9f97df8 100644 --- a/resources/scripts-v2/components/base/BaseCard.vue +++ b/resources/scripts-v2/components/base/BaseCard.vue @@ -1,5 +1,5 @@