Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88650c2f3e | ||
|
|
ee76f31138 | ||
|
|
e1af9f56c4 | ||
|
|
fdd860c381 | ||
|
|
5ff051fbb5 | ||
|
|
0d7059fcf6 | ||
|
|
7d9fdb79cc | ||
|
|
3d871604ae | ||
|
|
1adebe85b9 | ||
|
|
defbfc6406 | ||
|
|
25986b7bd5 | ||
|
|
751bd4a1c8 | ||
|
|
0e313b80ca | ||
|
|
5014a75fbc | ||
|
|
9e5b9fdaad | ||
|
|
08dfe62312 | ||
|
|
f623cd0179 | ||
|
|
77fd96d499 | ||
|
|
2e4e19dfc5 | ||
|
|
76c02be219 | ||
|
|
414531524c | ||
|
|
d75a957183 | ||
|
|
63d3a7fc8e | ||
|
|
0be747a483 | ||
|
|
3ceb08bc31 | ||
|
|
ad5a7e51b9 | ||
|
|
691178857f | ||
|
|
a38f09cf7b | ||
|
|
de4ba6bba0 | ||
|
|
375cfc6b18 | ||
|
|
aa88dc340d | ||
|
|
7004bf375e | ||
|
|
80889293bf | ||
|
|
d754c4d29e | ||
|
|
8de32e27d3 | ||
|
|
3bae2c282c | ||
|
|
14b5aaa0c9 | ||
|
|
aafcf147cf | ||
|
|
3c31baf20d | ||
|
|
a386fd19fc | ||
|
|
e5f6984078 | ||
|
|
d2953e9409 |
@@ -10,7 +10,7 @@ metadata:
|
||||
|
||||
## Documentation
|
||||
|
||||
Use `search-docs` for detailed Tailwind CSS v3 patterns and documentation.
|
||||
Use `search-docs` for detailed Tailwind CSS v4 patterns and documentation.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
@@ -18,22 +18,55 @@ Use `search-docs` for detailed Tailwind CSS v3 patterns and documentation.
|
||||
- Offer to extract repeated patterns into components that match the project's conventions (e.g., Blade, JSX, Vue).
|
||||
- Consider class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child elements carefully to reduce repetition, and group elements logically.
|
||||
|
||||
## Tailwind CSS v3 Specifics
|
||||
## Tailwind CSS v4 Specifics
|
||||
|
||||
- Always use Tailwind CSS v3 and verify you're using only classes it supports.
|
||||
- Configuration is done in the `tailwind.config.js` file.
|
||||
- Import using `@tailwind` directives:
|
||||
- Always use Tailwind CSS v4 and avoid deprecated utilities.
|
||||
- `corePlugins` is not supported in Tailwind v4.
|
||||
|
||||
<!-- v3 Import Syntax -->
|
||||
### CSS-First Configuration
|
||||
|
||||
In Tailwind v4, configuration is CSS-first using the `@theme` directive — no separate `tailwind.config.js` file is needed:
|
||||
|
||||
<!-- CSS-First Config -->
|
||||
```css
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@theme {
|
||||
--color-brand: oklch(0.72 0.11 178);
|
||||
}
|
||||
```
|
||||
|
||||
### Import Syntax
|
||||
|
||||
In Tailwind v4, import Tailwind with a regular CSS `@import` statement instead of the `@tailwind` directives used in v3:
|
||||
|
||||
<!-- v4 Import Syntax -->
|
||||
```diff
|
||||
- @tailwind base;
|
||||
- @tailwind components;
|
||||
- @tailwind utilities;
|
||||
+ @import "tailwindcss";
|
||||
```
|
||||
|
||||
### Replaced Utilities
|
||||
|
||||
Tailwind v4 removed deprecated utilities. Use the replacements shown below. Opacity values remain numeric.
|
||||
|
||||
| Deprecated | Replacement |
|
||||
|------------|-------------|
|
||||
| bg-opacity-* | bg-black/* |
|
||||
| text-opacity-* | text-black/* |
|
||||
| border-opacity-* | border-black/* |
|
||||
| divide-opacity-* | divide-black/* |
|
||||
| ring-opacity-* | ring-black/* |
|
||||
| placeholder-opacity-* | placeholder-black/* |
|
||||
| flex-shrink-* | shrink-* |
|
||||
| flex-grow-* | grow-* |
|
||||
| overflow-ellipsis | text-ellipsis |
|
||||
| decoration-slice | box-decoration-slice |
|
||||
| decoration-clone | box-decoration-clone |
|
||||
|
||||
## Spacing
|
||||
|
||||
When listing items, use gap utilities for spacing; don't use margins.
|
||||
Use `gap` utilities instead of margins for spacing between siblings:
|
||||
|
||||
<!-- Gap Utilities -->
|
||||
```html
|
||||
@@ -77,15 +110,10 @@ If existing pages and components support dark mode, new pages and components mus
|
||||
</div>
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
1. Check browser for visual rendering
|
||||
2. Test responsive breakpoints
|
||||
3. Verify dark mode if project uses it
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Using deprecated v3 utilities (bg-opacity-*, flex-shrink-*, etc.)
|
||||
- Using `@tailwind` directives instead of `@import "tailwindcss"`
|
||||
- Trying to use `tailwind.config.js` instead of CSS `@theme` directive
|
||||
- Using margins for spacing between siblings instead of gap utilities
|
||||
- Forgetting to add dark mode variants when the project uses dark mode
|
||||
- Not checking existing project conventions before adding new utilities
|
||||
- Overusing inline styles when Tailwind classes would suffice
|
||||
- Forgetting to add dark mode variants when the project uses dark mode
|
||||
@@ -1,14 +0,0 @@
|
||||
// .eslintrc.js
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
// add more generic rulesets here, such as:
|
||||
// 'eslint:recommended',
|
||||
"plugin:vue/vue3-recommended",
|
||||
"prettier",
|
||||
],
|
||||
rules: {
|
||||
// override/add rules settings here, such as:
|
||||
// 'vue/no-unused-vars': 'error'
|
||||
},
|
||||
};
|
||||
43
.github/workflows/check.yaml
vendored
43
.github/workflows/check.yaml
vendored
@@ -3,28 +3,41 @@ name: Check
|
||||
# Run this workflow every time a new commit pushed to your repository
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '.github/**/*'
|
||||
- '**/*.md'
|
||||
- 'public/build/*.js'
|
||||
- 'public/build/**/*.js'
|
||||
- 'docker/**/*'
|
||||
- 'resources/scripts/**/*'
|
||||
tags-ignore:
|
||||
- "*"
|
||||
branches-ignore:
|
||||
- 'translations'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- 'public/build/*.js'
|
||||
- 'public/build/**/*.js'
|
||||
branches-ignore:
|
||||
- 'translations'
|
||||
# Allow manually triggering the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: 🔍 Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
php: ${{ steps.filter.outputs.php }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for file changes
|
||||
uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
php:
|
||||
- 'app/**'
|
||||
- 'config/**'
|
||||
- 'database/**'
|
||||
- 'routes/**'
|
||||
- 'tests/**'
|
||||
- 'composer.json'
|
||||
- 'composer.lock'
|
||||
- 'phpunit.xml'
|
||||
|
||||
kill_previous:
|
||||
name: 0️⃣ Kill previous runs
|
||||
runs-on: ubuntu-latest
|
||||
@@ -41,6 +54,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- kill_previous
|
||||
- changes
|
||||
if: needs.changes.outputs.php == 'true'
|
||||
steps:
|
||||
- name: Set up PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
@@ -60,6 +75,8 @@ jobs:
|
||||
name: 2️⃣ PHP ${{ matrix.php-version }} Tests
|
||||
needs:
|
||||
- php_syntax_errors
|
||||
- changes
|
||||
if: needs.changes.outputs.php == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -83,10 +100,10 @@ jobs:
|
||||
- name: Install Composer dependencies
|
||||
uses: ramsey/composer-install@v2
|
||||
|
||||
- name: Use Node.js 20
|
||||
- name: Use Node.js 24
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
|
||||
- name: Install
|
||||
run: npm install
|
||||
|
||||
8
.github/workflows/docker.yaml
vendored
8
.github/workflows/docker.yaml
vendored
@@ -61,10 +61,10 @@ jobs:
|
||||
- name: Install Composer dependencies
|
||||
uses: ramsey/composer-install@v2
|
||||
|
||||
- name: Use Node.js 20
|
||||
- name: Use Node.js 24
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
|
||||
- name: Install
|
||||
run: npm install
|
||||
@@ -100,10 +100,10 @@ jobs:
|
||||
with:
|
||||
composer-options: --no-dev
|
||||
|
||||
- name: Use Node.js 20
|
||||
- name: Use Node.js 24
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
|
||||
- name: Install
|
||||
run: npm install
|
||||
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@@ -0,0 +1 @@
|
||||
24
|
||||
5909
.phpstorm.meta.php
Normal file
5909
.phpstorm.meta.php
Normal file
File diff suppressed because it is too large
Load Diff
80
CLAUDE.md
Normal file
80
CLAUDE.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
InvoiceShelf is an open-source invoicing and expense tracking application built with Laravel 13 (PHP 8.4) and Vue 3. It supports multi-company tenancy, customer portals, recurring invoices, and PDF generation.
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Development
|
||||
```bash
|
||||
composer run dev # Starts PHP server, queue listener, log tail, and Vite dev server concurrently
|
||||
npm run dev # Vite dev server only
|
||||
npm run build # Production frontend build
|
||||
```
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
php artisan test --compact # Run all tests
|
||||
php artisan test --compact --filter=testName # Run specific test
|
||||
./vendor/bin/pest --stop-on-failure # Run via Pest directly
|
||||
make test # Makefile shortcut
|
||||
```
|
||||
|
||||
Tests use SQLite in-memory DB, configured in `phpunit.xml`. Tests seed via `DatabaseSeeder` + `DemoSeeder` in `beforeEach`. Authenticate with `Sanctum::actingAs()` and set the `company` header.
|
||||
|
||||
### Code Style
|
||||
```bash
|
||||
vendor/bin/pint --dirty --format agent # Fix style on modified PHP files
|
||||
vendor/bin/pint --test # Check style without fixing (CI uses this)
|
||||
```
|
||||
|
||||
### Artisan Generators
|
||||
Always use `php artisan make:*` with `--no-interaction` to create new files (models, controllers, migrations, tests, etc.).
|
||||
|
||||
## Architecture
|
||||
|
||||
### Multi-Tenancy
|
||||
Every major model has a `company_id` foreign key. The `CompanyMiddleware` sets the active company from the `company` request header. Bouncer authorization is scoped to the company level via `DefaultScope` (`app/Bouncer/Scopes/DefaultScope.php`).
|
||||
|
||||
### Authentication
|
||||
Three guards: `web` (session), `api` (Sanctum tokens for `/api/v1/`), `customer` (session for customer portal). API routes use `auth:sanctum` middleware; customer portal uses `auth:customer`.
|
||||
|
||||
### Routing
|
||||
- **API**: All endpoints under `/api/v1/` in `routes/api.php`, grouped with `auth:sanctum`, `company`, and `bouncer` middleware
|
||||
- **Web**: `routes/web.php` serves PDF endpoints, auth pages, and catch-all SPA routes (`/admin/{vue?}`, `/{company:slug}/customer/{vue?}`)
|
||||
|
||||
### Frontend
|
||||
- Entry point: `resources/scripts/main.js`
|
||||
- Vue Router: `resources/scripts/admin/admin-router.js` (admin), `resources/scripts/customer/customer-router.js` (customer portal)
|
||||
- State: Pinia stores in `resources/scripts/admin/stores/`
|
||||
- Path aliases: `@` = `resources/`, `$fonts`, `$images` for static assets
|
||||
- Vite dev server expects `invoiceshelf.test` hostname
|
||||
|
||||
### Backend Patterns
|
||||
- **Authorization**: Silber/Bouncer with policies in `app/Policies/`. Controllers use `$this->authorize()`.
|
||||
- **Validation**: Form Request classes, never inline validation
|
||||
- **API responses**: Eloquent API Resources in `app/Http/Resources/`
|
||||
- **PDF generation**: DomPDF (`GeneratesPdfTrait`) or Gotenberg
|
||||
- **Email**: Mailable classes with `EmailLog` tracking
|
||||
- **File storage**: Spatie MediaLibrary, supports local/S3/Dropbox
|
||||
- **Serial numbers**: `SerialNumberFormatter` service
|
||||
- **Company settings**: `CompanySetting` model (key-value per company)
|
||||
|
||||
### Database
|
||||
Supports MySQL, PostgreSQL, and SQLite. Prefer Eloquent over raw queries. Use `Model::query()` instead of `DB::`. Use eager loading to prevent N+1 queries.
|
||||
|
||||
## Code Conventions
|
||||
|
||||
- PHP: snake_case, constructor property promotion, explicit return types, PHPDoc blocks over inline comments
|
||||
- JS: camelCase
|
||||
- Always check sibling files for patterns before creating new ones
|
||||
- Use `config()` helper, never `env()` outside config files
|
||||
- Every change must have tests (feature tests preferred over unit tests)
|
||||
- Run `vendor/bin/pint --dirty --format agent` after modifying PHP files
|
||||
|
||||
## CI Pipeline
|
||||
|
||||
GitHub Actions (`check.yaml`): runs Pint style check, then builds frontend and runs Pest tests on PHP 8.4.
|
||||
12337
_ide_helper.php
12337
_ide_helper.php
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@ class ResetApp extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Clean database, database_created and public/storage folder';
|
||||
protected $description = 'Clean database and public/storage folder';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace App\Http\Controllers\V1\Admin\Backup;
|
||||
|
||||
use App\Jobs\CreateBackupJob;
|
||||
use App\Models\FileDisk;
|
||||
use App\Rules\Backup\PathToZip;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -27,6 +28,16 @@ class BackupsController extends ApiController
|
||||
$configuredBackupDisks = config('backup.backup.destination.disks');
|
||||
|
||||
try {
|
||||
if ($request->file_disk_id) {
|
||||
$fileDisk = FileDisk::find($request->file_disk_id);
|
||||
if ($fileDisk) {
|
||||
$fileDisk->setConfig();
|
||||
$prefix = env('DYNAMIC_DISK_PREFIX', 'temp_');
|
||||
config(['backup.backup.destination.disks' => [$prefix.$fileDisk->driver]]);
|
||||
$configuredBackupDisks = config('backup.backup.destination.disks');
|
||||
}
|
||||
}
|
||||
|
||||
$backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name'));
|
||||
|
||||
$backups = Cache::remember("backups-{$request->file_disk_id}", now()->addSeconds(4), function () use ($backupDestination) {
|
||||
@@ -65,7 +76,10 @@ class BackupsController extends ApiController
|
||||
{
|
||||
$this->authorize('manage backups');
|
||||
|
||||
dispatch(new CreateBackupJob($request->all()))->onQueue(config('backup.queue.name'));
|
||||
$data = $request->all();
|
||||
$data['company'] = $request->header('company');
|
||||
|
||||
dispatch(new CreateBackupJob($data))->onQueue(config('backup.queue.name'));
|
||||
|
||||
return $this->respondSuccess();
|
||||
}
|
||||
|
||||
@@ -61,10 +61,10 @@ class CompaniesController extends Controller
|
||||
$company = Company::find($request->header('company'));
|
||||
$this->authorize('transfer company ownership', $company);
|
||||
|
||||
if ($user->hasCompany($company->id)) {
|
||||
if (! $user->hasCompany($company->id)) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'User does not belongs to this company.',
|
||||
'message' => 'User does not belong to this company.',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,11 @@ class CustomersController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple customers');
|
||||
|
||||
Customer::deleteCustomers($request->ids);
|
||||
$ids = Customer::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Customer::deleteCustomers($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -21,6 +21,7 @@ class CloneEstimateController extends Controller
|
||||
*/
|
||||
public function __invoke(Request $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('view', $estimate);
|
||||
$this->authorize('create', Estimate::class);
|
||||
|
||||
$date = Carbon::now();
|
||||
|
||||
@@ -68,7 +68,11 @@ class EstimatesController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple estimates');
|
||||
|
||||
Estimate::destroy($request->ids);
|
||||
$ids = Estimate::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Estimate::destroy($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -81,7 +81,11 @@ class ExpensesController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple expenses');
|
||||
|
||||
Expense::destroy($request->ids);
|
||||
$ids = Expense::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Expense::destroy($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -25,7 +25,8 @@ class SearchController extends Controller
|
||||
->paginate(10);
|
||||
|
||||
if ($user->isOwner()) {
|
||||
$users = User::applyFilters($request->only(['search']))
|
||||
$users = User::whereCompany()
|
||||
->applyFilters($request->only(['search']))
|
||||
->latest()
|
||||
->paginate(10);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class CloneInvoiceController extends Controller
|
||||
*/
|
||||
public function __invoke(Request $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('view', $invoice);
|
||||
$this->authorize('create', Invoice::class);
|
||||
|
||||
$date = Carbon::now();
|
||||
|
||||
@@ -100,7 +100,11 @@ class InvoicesController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple invoices');
|
||||
|
||||
Invoice::deleteInvoices($request->ids);
|
||||
$ids = Invoice::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Invoice::deleteInvoices($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -90,7 +90,11 @@ class ItemsController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple items');
|
||||
|
||||
Item::destroy($request->ids);
|
||||
$ids = Item::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Item::destroy($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -73,7 +73,11 @@ class PaymentsController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple payments');
|
||||
|
||||
Payment::deletePayments($request->ids);
|
||||
$ids = Payment::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Payment::deletePayments($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -84,7 +84,11 @@ class RecurringInvoiceController extends Controller
|
||||
{
|
||||
$this->authorize('delete multiple recurring invoices');
|
||||
|
||||
RecurringInvoice::deleteRecurringInvoice($request->ids);
|
||||
$ids = RecurringInvoice::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
RecurringInvoice::deleteRecurringInvoice($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
|
||||
@@ -165,11 +165,11 @@ class MailConfigurationController extends Controller
|
||||
switch ($driver) {
|
||||
case 'smtp':
|
||||
$MailData = array_merge($MailData, [
|
||||
'mail_host' => $mailSettings['mail_host'] ?? '',
|
||||
'mail_port' => $mailSettings['mail_port'] ?? '',
|
||||
'mail_username' => $mailSettings['mail_username'] ?? '',
|
||||
'mail_password' => $mailSettings['mail_password'] ?? '',
|
||||
'mail_encryption' => $mailSettings['mail_encryption'] ?? 'none',
|
||||
'mail_host' => $mailSettings['mail_host'] ?? config('mail.mailers.smtp.host', ''),
|
||||
'mail_port' => $mailSettings['mail_port'] ?? config('mail.mailers.smtp.port', ''),
|
||||
'mail_username' => $mailSettings['mail_username'] ?? config('mail.mailers.smtp.username', ''),
|
||||
'mail_password' => $mailSettings['mail_password'] ?? config('mail.mailers.smtp.password', ''),
|
||||
'mail_encryption' => $mailSettings['mail_encryption'] ?? config('mail.mailers.smtp.encryption', 'none'),
|
||||
'mail_scheme' => $mailSettings['mail_scheme'] ?? '',
|
||||
'mail_url' => $mailSettings['mail_url'] ?? '',
|
||||
'mail_timeout' => $mailSettings['mail_timeout'] ?? '',
|
||||
|
||||
@@ -25,14 +25,15 @@ class UsersController extends Controller
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
$users = User::applyFilters($request->all())
|
||||
$users = User::whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->where('id', '<>', $user->id)
|
||||
->latest()
|
||||
->paginate($limit);
|
||||
|
||||
return UserResource::collection($users)
|
||||
->additional(['meta' => [
|
||||
'user_total_count' => User::count(),
|
||||
'user_total_count' => User::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,9 @@ class DatabaseConfigurationController extends Controller
|
||||
public function getDatabaseEnvironment(Request $request)
|
||||
{
|
||||
$databaseData = [];
|
||||
$connection = $request->connection ?? config('database.default');
|
||||
|
||||
switch ($request->connection) {
|
||||
switch ($connection) {
|
||||
case 'sqlite':
|
||||
$databaseData = [
|
||||
'database_connection' => 'sqlite',
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Http\Controllers\V1\Installation;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Space\InstallUtils;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -16,10 +15,6 @@ class FinishController extends Controller
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
if (! InstallUtils::createDbMarker()) {
|
||||
\Log::error('Install: Unable to create db marker.');
|
||||
}
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class OnboardingWizardController extends Controller
|
||||
*/
|
||||
public function getStep(Request $request)
|
||||
{
|
||||
if (! InstallUtils::dbMarkerExists()) {
|
||||
if (! InstallUtils::isDbCreated()) {
|
||||
return response()->json([
|
||||
'profile_complete' => 0,
|
||||
'profile_language' => 'en',
|
||||
|
||||
@@ -17,7 +17,11 @@ class InstallationMiddleware
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (! InstallUtils::isDbCreated() || Setting::getSetting('profile_complete') !== 'COMPLETED') {
|
||||
try {
|
||||
if (! InstallUtils::isDbCreated() || Setting::getSetting('profile_complete') !== 'COMPLETED') {
|
||||
return redirect('/installation');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return redirect('/installation');
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,13 @@ class RedirectIfInstalled
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (InstallUtils::dbMarkerExists()) {
|
||||
if (Setting::getSetting('profile_complete') === 'COMPLETED') {
|
||||
return redirect('login');
|
||||
if (InstallUtils::isDbCreated()) {
|
||||
try {
|
||||
if (Setting::getSetting('profile_complete') === 'COMPLETED') {
|
||||
return redirect('login');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Settings table may not exist yet during installation
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\FileDisk;
|
||||
use App\Space\BackupConfigurationFactory;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Spatie\Backup\Config\Config;
|
||||
use Spatie\Backup\Tasks\Backup\BackupJobFactory;
|
||||
|
||||
class CreateBackupJob implements ShouldQueue
|
||||
@@ -25,7 +24,7 @@ class CreateBackupJob implements ShouldQueue
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data = '')
|
||||
public function __construct($data = [])
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
@@ -35,14 +34,7 @@ class CreateBackupJob implements ShouldQueue
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$fileDisk = FileDisk::find($this->data['file_disk_id']);
|
||||
$fileDisk->setConfig();
|
||||
|
||||
$prefix = env('DYNAMIC_DISK_PREFIX', 'temp_');
|
||||
|
||||
config(['backup.backup.destination.disks' => [$prefix.$fileDisk->driver]]);
|
||||
|
||||
$config = Config::fromArray(config('backup'));
|
||||
$config = BackupConfigurationFactory::make($this->data);
|
||||
$backupJob = BackupJobFactory::createFromConfig($config);
|
||||
if (! defined('SIGINT')) {
|
||||
$backupJob->disableSignals();
|
||||
|
||||
@@ -213,6 +213,13 @@ class User extends Authenticatable implements HasMedia
|
||||
return $query->where('email', 'LIKE', '%'.$email.'%');
|
||||
}
|
||||
|
||||
public function scopeWhereCompany($query)
|
||||
{
|
||||
return $query->whereHas('companies', function ($q) {
|
||||
$q->where('company_id', request()->header('company'));
|
||||
});
|
||||
}
|
||||
|
||||
public function scopePaginateData($query, $limit)
|
||||
{
|
||||
if ($limit == 'all') {
|
||||
|
||||
@@ -32,7 +32,7 @@ class CustomerPolicy
|
||||
*/
|
||||
public function view(User $user, Customer $customer): bool
|
||||
{
|
||||
if (BouncerFacade::can('view-customer', $customer)) {
|
||||
if (BouncerFacade::can('view-customer', $customer) && $user->hasCompany($customer->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class CustomerPolicy
|
||||
*/
|
||||
public function update(User $user, Customer $customer): bool
|
||||
{
|
||||
if (BouncerFacade::can('edit-customer', $customer)) {
|
||||
if (BouncerFacade::can('edit-customer', $customer) && $user->hasCompany($customer->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class CustomerPolicy
|
||||
*/
|
||||
public function delete(User $user, Customer $customer): bool
|
||||
{
|
||||
if (BouncerFacade::can('delete-customer', $customer)) {
|
||||
if (BouncerFacade::can('delete-customer', $customer) && $user->hasCompany($customer->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class CustomerPolicy
|
||||
*/
|
||||
public function restore(User $user, Customer $customer): bool
|
||||
{
|
||||
if (BouncerFacade::can('delete-customer', $customer)) {
|
||||
if (BouncerFacade::can('delete-customer', $customer) && $user->hasCompany($customer->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ class CustomerPolicy
|
||||
*/
|
||||
public function forceDelete(User $user, Customer $customer): bool
|
||||
{
|
||||
if (BouncerFacade::can('delete-customer', $customer)) {
|
||||
if (BouncerFacade::can('delete-customer', $customer) && $user->hasCompany($customer->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
40
app/Space/BackupConfigurationFactory.php
Normal file
40
app/Space/BackupConfigurationFactory.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Space;
|
||||
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\FileDisk;
|
||||
use Exception;
|
||||
use Spatie\Backup\Config\Config;
|
||||
|
||||
class BackupConfigurationFactory
|
||||
{
|
||||
public static function make($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');
|
||||
}
|
||||
|
||||
$fileDisk = FileDisk::find($data['file_disk_id']);
|
||||
|
||||
$fileDisk->setConfig();
|
||||
|
||||
$prefix = env('DYNAMIC_DISK_PREFIX', 'temp_');
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@ namespace App\Space;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use League\Flysystem\FilesystemException;
|
||||
|
||||
class InstallUtils
|
||||
{
|
||||
@@ -17,7 +15,7 @@ class InstallUtils
|
||||
*/
|
||||
public static function isDbCreated()
|
||||
{
|
||||
return self::dbMarkerExists() && self::tableExists('users');
|
||||
return self::tableExists('users');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,54 +42,6 @@ class InstallUtils
|
||||
return $cache[$table];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if database created marker exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function dbMarkerExists()
|
||||
{
|
||||
try {
|
||||
return \Storage::disk('local')->has('database_created');
|
||||
} catch (FilesystemException $e) {
|
||||
Log::error('Unable to verify db marker: '.$e->getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the database marker
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function createDbMarker()
|
||||
{
|
||||
try {
|
||||
return \Storage::disk('local')->put('database_created', time());
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Unable to create db marker: '.$e->getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the database marker
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function deleteDbMarker()
|
||||
{
|
||||
try {
|
||||
return \Storage::disk('local')->delete('database_created');
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Unable to delete db marker: '.$e->getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the app version
|
||||
*
|
||||
|
||||
@@ -19,6 +19,9 @@ final class PdfHtmlSanitizer
|
||||
return '';
|
||||
}
|
||||
|
||||
// Legacy/invalid `</br>` is dropped by libxml and collapses lines in PDF output; normalize to `<br />`.
|
||||
$html = str_replace('</br>', '<br />', $html);
|
||||
|
||||
$allowedTags = '<br><br/><p><b><strong><i><em><u><ol><ul><li><table><tr><td><th><thead><tbody><tfoot><h1><h2><h3><h4><blockquote>';
|
||||
$html = strip_tags($html, $allowedTags);
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ trait GeneratesPdfTrait
|
||||
|
||||
$str = str_replace('<p>', '', $str);
|
||||
|
||||
$str = str_replace('</p>', '</br>', $str);
|
||||
$str = str_replace('</p>', '<br />', $str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
@@ -9,15 +9,12 @@
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": "^8.4",
|
||||
"aws/aws-sdk-php": "^3.336",
|
||||
"barryvdh/laravel-dompdf": "^v3.0",
|
||||
"doctrine/dbal": "^4.2",
|
||||
"dragonmantank/cron-expression": "^v3.4",
|
||||
"gotenberg/gotenberg-php": "^2.8",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"hashids/hashids": "^5.0",
|
||||
"invoiceshelf/modules": "^1.0.0",
|
||||
"jasonmccreary/laravel-test-assertions": "^v2.4",
|
||||
"laravel/framework": "^13.0",
|
||||
"laravel/helpers": "^1.7",
|
||||
"laravel/sanctum": "^4.0",
|
||||
@@ -36,6 +33,7 @@
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-ide-helper": "^3.5",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"jasonmccreary/laravel-test-assertions": "^2.9",
|
||||
"laravel/boost": "^2.3",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.41",
|
||||
@@ -83,7 +81,11 @@
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
|
||||
]
|
||||
],
|
||||
"ide-helper": [
|
||||
"@php artisan ide-helper:generate",
|
||||
"@php artisan ide-helper:meta"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
|
||||
3915
composer.lock
generated
3915
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,15 @@ return [
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'visibility' => 'public',
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_KEY'),
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Models\CompanySetting;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Space\InstallUtils;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
@@ -71,8 +70,5 @@ class DemoSeeder extends Seeder
|
||||
|
||||
// Mark profile setup as complete
|
||||
Setting::setSetting('profile_complete', 'COMPLETED');
|
||||
|
||||
// Create installation marker
|
||||
InstallUtils::createDbMarker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
FROM --platform=$BUILDPLATFORM node AS static_builder
|
||||
FROM --platform=$BUILDPLATFORM node:24 AS static_builder
|
||||
WORKDIR /var/www/html
|
||||
COPY . /var/www/html
|
||||
RUN yarn && yarn build
|
||||
|
||||
FROM serversideup/php:8.4-fpm-alpine AS base
|
||||
USER root
|
||||
RUN apk add --no-cache sqlite
|
||||
RUN apk add --no-cache bash nano mariadb-client postgresql-client sqlite
|
||||
RUN install-php-extensions exif
|
||||
RUN install-php-extensions pgsql
|
||||
RUN install-php-extensions sqlite3
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
FROM --platform=$BUILDPLATFORM node:20 AS static_builder
|
||||
FROM --platform=$BUILDPLATFORM node:24 AS static_builder
|
||||
WORKDIR /var/www/html
|
||||
COPY . /var/www/html
|
||||
RUN yarn && yarn build
|
||||
|
||||
FROM serversideup/php:8.4-fpm-nginx-alpine AS base
|
||||
USER root
|
||||
RUN apk add --no-cache bash nano
|
||||
RUN apk add --no-cache bash nano mariadb-client postgresql-client sqlite
|
||||
RUN install-php-extensions exif
|
||||
RUN install-php-extensions pgsql
|
||||
RUN install-php-extensions sqlite3
|
||||
@@ -19,6 +19,10 @@ FROM serversideup/php:8.4-fpm-nginx-alpine AS base
|
||||
RUN install-php-extensions intl
|
||||
RUN install-php-extensions curl
|
||||
|
||||
# Copy entrypoint and inject script, and make sure they are executable
|
||||
COPY --chmod=755 docker/production/inject.sh /inject.sh
|
||||
COPY --chmod=755 docker/production/entrypoint.d/ /etc/entrypoint.d/
|
||||
|
||||
FROM base AS production
|
||||
ENV AUTORUN_ENABLED=true
|
||||
ENV PHP_OPCACHE_ENABLE=1
|
||||
@@ -36,7 +40,3 @@ FROM base AS production
|
||||
COPY --from=static_builder --chown=www-data:www-data /var/www/html/public /var/www/html/public
|
||||
COPY --chown=www-data:www-data . /var/www/html
|
||||
RUN composer install --prefer-dist --no-dev --optimize-autoloader
|
||||
|
||||
# Copy entrypoint and inject script, and make sure they are executable
|
||||
COPY --chmod=755 docker/production/inject.sh /inject.sh
|
||||
COPY --chmod=755 docker/production/entrypoint.d/ /etc/entrypoint.d/
|
||||
|
||||
@@ -33,8 +33,15 @@ if [ "$DB_CONNECTION" = "sqlite" ] || [ -z "$DB_CONNECTION" ]; then
|
||||
chown www-data:www-data "$DB_DATABASE"
|
||||
fi
|
||||
|
||||
echo "**** Setting up artisan permissions ****"
|
||||
echo "**** Setting up folder permissions ****"
|
||||
chmod +x artisan
|
||||
chown -R www-data:www-data storage bootstrap/cache
|
||||
chmod -R 775 storage bootstrap/cache
|
||||
|
||||
if [ ! -L /var/www/html/public/storage ]; then
|
||||
echo "**** Creating storage symlink (public/storage) ****"
|
||||
./artisan storage:link --force -n || true
|
||||
fi
|
||||
|
||||
if ! grep -q "APP_KEY" /var/www/html/.env
|
||||
then
|
||||
|
||||
13
eslint.config.mjs
Normal file
13
eslint.config.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
import pluginVue from 'eslint-plugin-vue'
|
||||
import eslintConfigPrettier from 'eslint-config-prettier'
|
||||
|
||||
export default [
|
||||
...pluginVue.configs['flat/recommended'],
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
files: ['resources/scripts/**/*.{js,vue}'],
|
||||
rules: {
|
||||
'vue/no-mutating-props': 'off',
|
||||
},
|
||||
},
|
||||
]
|
||||
55
package.json
55
package.json
@@ -1,64 +1,61 @@
|
||||
{
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"watch": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"test": "eslint ./resources/scripts --ext .js,.vue"
|
||||
"test": "eslint ./resources/scripts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rvxlab/tailwind-plugin-ios-full-height": "^1.1.0",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"@vue/compiler-sfc": "^3.5.13",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"postcss": "^8.4.49",
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"sass": "^1.83.1",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss": "^3.4.17"
|
||||
"tailwind-scrollbar": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/vue": "^1.7.23",
|
||||
"@heroicons/vue": "^2.2.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@stripe/stripe-js": "^2.4.0",
|
||||
"@tiptap/core": "^2.11.2",
|
||||
"@tiptap/extension-link": "^2.11.2",
|
||||
"@tiptap/extension-text-align": "^2.11.2",
|
||||
"@tiptap/pm": "^2.11.2",
|
||||
"@tiptap/starter-kit": "^2.11.2",
|
||||
"@tiptap/vue-3": "^2.11.2",
|
||||
"@types/node": "^20.11.9",
|
||||
"@tiptap/core": "^3.0.0",
|
||||
"@tiptap/extension-text-align": "^3.0.0",
|
||||
"@tiptap/pm": "^3.0.0",
|
||||
"@tiptap/starter-kit": "^3.0.0",
|
||||
"@tiptap/vue-3": "^3.0.0",
|
||||
"@types/node": "^24.0.0",
|
||||
"@vuelidate/components": "^1.2.6",
|
||||
"@vuelidate/core": "^2.0.3",
|
||||
"@vuelidate/validators": "^2.0.4",
|
||||
"@vueuse/core": "^12.4.0",
|
||||
"axios": "0.30.0",
|
||||
"chart.js": "^2.9.4",
|
||||
"@vueuse/core": "^14.0.0",
|
||||
"axios": "1.14.0",
|
||||
"chart.js": "^4.5.1",
|
||||
"guid": "^0.0.12",
|
||||
"laravel-vite-plugin": "^1.1.1",
|
||||
"laravel-vite-plugin": "^3.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"maska": "^3.0.4",
|
||||
"mini-svg-data-uri": "^1.4.4",
|
||||
"moment": "^2.30.1",
|
||||
"path": "^0.12.7",
|
||||
"pinia": "^2.3.0",
|
||||
"pinia": "^3.0.0",
|
||||
"v-money3": "^3.24.1",
|
||||
"v-tooltip": "^4.0.0-beta.17",
|
||||
"vite": "^6.0.7",
|
||||
"vite": "^8.0.0",
|
||||
"vue": "^3.5",
|
||||
"vue-flatpickr-component": "^11.0.5",
|
||||
"vue-flatpickr-component": "^12.0.0",
|
||||
"vue-i18n": "^11.0.1",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-router": "^5.0.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
56
resources/css/components/pace-loader.css
vendored
Normal file
56
resources/css/components/pace-loader.css
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
.pace {
|
||||
-webkit-pointer-events: none;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pace-inactive {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pace .pace-progress {
|
||||
background: #3f39ad;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 0;
|
||||
right: 100%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.pace .pace-progress-inner {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 10px #5851d8, 0 0 5px #5851d8;
|
||||
opacity: 1;
|
||||
transform: rotate(3deg) translate(0px, -4px);
|
||||
}
|
||||
|
||||
.pace .pace-activity {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: solid 2px transparent;
|
||||
border-top-color: #5851d8;
|
||||
border-left-color: #5851d8;
|
||||
border-radius: 10px;
|
||||
animation: pace-spinner 400ms linear infinite;
|
||||
}
|
||||
|
||||
@keyframes pace-spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@@ -80,18 +80,16 @@
|
||||
}
|
||||
|
||||
&.popover {
|
||||
$color: #f9f9f9;
|
||||
|
||||
.popover-inner {
|
||||
background: $color;
|
||||
background: #f9f9f9;
|
||||
color: black;
|
||||
padding: 24px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 5px 30px rgba(black, .1);
|
||||
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
border-color: $color;
|
||||
border-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
|
||||
98
resources/css/invoiceshelf.css
vendored
Normal file
98
resources/css/invoiceshelf.css
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
@import "tailwindcss";
|
||||
@import "./themes.css";
|
||||
@import "./components/animation.css";
|
||||
@import "./components/pace-loader.css";
|
||||
@import "./components/v-tooltips.css";
|
||||
|
||||
@plugin "@tailwindcss/forms";
|
||||
@plugin "@tailwindcss/typography";
|
||||
@plugin "tailwind-scrollbar";
|
||||
|
||||
@source "../scripts/**/*.vue";
|
||||
@source "../scripts/**/*.js";
|
||||
@source "../../resources/views/**/*.php";
|
||||
|
||||
@theme inline {
|
||||
--color-primary-50: var(--color-primary-50);
|
||||
--color-primary-100: var(--color-primary-100);
|
||||
--color-primary-200: var(--color-primary-200);
|
||||
--color-primary-300: var(--color-primary-300);
|
||||
--color-primary-400: var(--color-primary-400);
|
||||
--color-primary-500: var(--color-primary-500);
|
||||
--color-primary-600: var(--color-primary-600);
|
||||
--color-primary-700: var(--color-primary-700);
|
||||
--color-primary-800: var(--color-primary-800);
|
||||
--color-primary-900: var(--color-primary-900);
|
||||
--color-primary-950: var(--color-primary-950);
|
||||
--color-black: #040405;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--spacing-88: 22rem;
|
||||
--font-base: Poppins, sans-serif;
|
||||
}
|
||||
|
||||
@utility bg-multiselect-caret {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='h-5 w-5' viewBox='0 0 20 20' fill='currentColor'%3E%3Cpath fill-rule='evenodd' d='M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z' clip-rule='evenodd'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@utility bg-multiselect-spinner {
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' fill='%234a3dff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M456.433 371.72l-27.79-16.045c-7.192-4.152-10.052-13.136-6.487-20.636 25.82-54.328 23.566-118.602-6.768-171.03-30.265-52.529-84.802-86.621-144.76-91.424C262.35 71.922 256 64.953 256 56.649V24.56c0-9.31 7.916-16.609 17.204-15.96 81.795 5.717 156.412 51.902 197.611 123.408 41.301 71.385 43.99 159.096 8.042 232.792-4.082 8.369-14.361 11.575-22.424 6.92z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@utility bg-multiselect-remove {
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 320 512' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Black.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Light.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Medium.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-SemiBold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
min-height: -webkit-fill-available;
|
||||
}
|
||||
|
||||
html {
|
||||
height: -webkit-fill-available;
|
||||
}
|
||||
|
||||
.h-screen-ios {
|
||||
height: -webkit-fill-available;
|
||||
}
|
||||
13
resources/css/themes.css
vendored
Normal file
13
resources/css/themes.css
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
:root {
|
||||
--color-primary-50: rgb(241, 243, 255);
|
||||
--color-primary-100: rgb(229, 231, 255);
|
||||
--color-primary-200: rgb(206, 209, 255);
|
||||
--color-primary-300: rgb(167, 170, 255);
|
||||
--color-primary-400: rgb(118, 117, 255);
|
||||
--color-primary-500: rgb(74, 61, 255);
|
||||
--color-primary-600: rgb(51, 22, 255);
|
||||
--color-primary-700: rgb(33, 4, 253);
|
||||
--color-primary-800: rgb(27, 3, 211);
|
||||
--color-primary-900: rgb(25, 5, 173);
|
||||
--color-primary-950: rgb(9, 0, 118);
|
||||
}
|
||||
112
resources/sass/components/pace-loader.scss
vendored
112
resources/sass/components/pace-loader.scss
vendored
@@ -1,112 +0,0 @@
|
||||
$pace-loader-color: #5851d8;
|
||||
|
||||
.pace {
|
||||
-webkit-pointer-events: none;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pace-inactive {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pace .pace-progress {
|
||||
background: darken($pace-loader-color, 10%);
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 0;
|
||||
right: 100%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.pace .pace-progress-inner {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 10px $pace-loader-color, 0 0 5px $pace-loader-color;
|
||||
opacity: 1;
|
||||
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
||||
-moz-transform: rotate(3deg) translate(0px, -4px);
|
||||
-ms-transform: rotate(3deg) translate(0px, -4px);
|
||||
-o-transform: rotate(3deg) translate(0px, -4px);
|
||||
transform: rotate(3deg) translate(0px, -4px);
|
||||
}
|
||||
|
||||
.pace .pace-activity {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: solid 2px transparent;
|
||||
border-top-color: $pace-loader-color;
|
||||
border-left-color: $pace-loader-color;
|
||||
border-radius: 10px;
|
||||
-webkit-animation: pace-spinner 400ms linear infinite;
|
||||
-moz-animation: pace-spinner 400ms linear infinite;
|
||||
-ms-animation: pace-spinner 400ms linear infinite;
|
||||
-o-animation: pace-spinner 400ms linear infinite;
|
||||
animation: pace-spinner 400ms linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes pace-spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes pace-spinner {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-moz-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes pace-spinner {
|
||||
0% {
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-ms-keyframes pace-spinner {
|
||||
0% {
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pace-spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
61
resources/sass/invoiceshelf.scss
vendored
61
resources/sass/invoiceshelf.scss
vendored
@@ -1,61 +0,0 @@
|
||||
@use "themes.scss";
|
||||
@use "components/animation.scss";
|
||||
|
||||
@tailwind base;
|
||||
|
||||
@tailwind components;
|
||||
|
||||
@tailwind utilities;
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Black.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Light.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Medium.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("$fonts/Poppins-SemiBold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
min-height: -webkit-fill-available;
|
||||
}
|
||||
|
||||
html {
|
||||
height: -webkit-fill-available;
|
||||
}
|
||||
|
||||
.h-screen-ios {
|
||||
height: -webkit-fill-available;
|
||||
}
|
||||
13
resources/sass/themes.scss
vendored
13
resources/sass/themes.scss
vendored
@@ -1,13 +0,0 @@
|
||||
:root {
|
||||
--color-primary-50: 241, 243, 255;
|
||||
--color-primary-100: 229, 231, 255;
|
||||
--color-primary-200: 206, 209, 255;
|
||||
--color-primary-300: 167, 170, 255;
|
||||
--color-primary-400: 118, 117, 255;
|
||||
--color-primary-500: 74, 61, 255;
|
||||
--color-primary-600: 51, 22, 255;
|
||||
--color-primary-700: 33, 4, 253;
|
||||
--color-primary-800: 27, 3, 211;
|
||||
--color-primary-900: 25, 5, 173;
|
||||
--color-primary-950: 9, 0, 118;
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
px-4
|
||||
py-2
|
||||
rounded-lg
|
||||
bg-opacity-40 bg-gray-300
|
||||
bg-gray-300/40
|
||||
whitespace-nowrap
|
||||
flex-col
|
||||
mt-1
|
||||
@@ -33,7 +33,7 @@
|
||||
h-full
|
||||
inset-y-0
|
||||
cursor-pointer
|
||||
focus:outline-none
|
||||
focus:outline-hidden
|
||||
text-primary-500
|
||||
"
|
||||
width="37"
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
<Popover v-slot="{ isOpen }">
|
||||
<PopoverButton
|
||||
v-if="userStore.hasAbilities(abilities.VIEW_NOTE)"
|
||||
:class="isOpen ? '' : 'text-opacity-90'"
|
||||
:class="isOpen ? '' : ''"
|
||||
class="
|
||||
flex
|
||||
items-center
|
||||
z-10
|
||||
font-medium
|
||||
text-primary-400
|
||||
focus:outline-none focus:border-none
|
||||
focus:outline-hidden focus:border-none
|
||||
"
|
||||
@click="fetchInitialData"
|
||||
>
|
||||
@@ -50,7 +50,7 @@
|
||||
overflow-hidden
|
||||
rounded-md
|
||||
shadow-lg
|
||||
ring-1 ring-black ring-opacity-5
|
||||
ring-1 ring-black/5
|
||||
"
|
||||
>
|
||||
<div class="relative grid bg-white">
|
||||
@@ -117,7 +117,7 @@
|
||||
py-3
|
||||
bg-gray-200
|
||||
border-none
|
||||
outline-none
|
||||
outline-hidden
|
||||
"
|
||||
@click="openNoteModal"
|
||||
>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Chart from 'chart.js'
|
||||
import { Chart } from 'chart.js/auto'
|
||||
import { ref, reactive, computed, onMounted, watchEffect, inject } from 'vue'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
|
||||
@@ -65,19 +65,21 @@ onMounted(() => {
|
||||
let options = reactive({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
callbacks: {
|
||||
label: function (tooltipItem, data) {
|
||||
return utils.formatMoney(
|
||||
Math.round(tooltipItem.value * 100),
|
||||
defaultCurrency.value
|
||||
)
|
||||
plugins: {
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
callbacks: {
|
||||
label: function (context) {
|
||||
return utils.formatMoney(
|
||||
Math.round(context.parsed.y * 100),
|
||||
defaultCurrency.value
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -87,7 +89,7 @@ onMounted(() => {
|
||||
{
|
||||
label: 'Sales',
|
||||
fill: false,
|
||||
lineTension: 0.3,
|
||||
tension: 0.3,
|
||||
backgroundColor: 'rgba(230, 254, 249)',
|
||||
borderColor: '#040405',
|
||||
borderCapStyle: 'butt',
|
||||
@@ -108,7 +110,7 @@ onMounted(() => {
|
||||
{
|
||||
label: 'Receipts',
|
||||
fill: false,
|
||||
lineTension: 0.3,
|
||||
tension: 0.3,
|
||||
backgroundColor: 'rgba(230, 254, 249)',
|
||||
borderColor: 'rgb(2, 201, 156)',
|
||||
borderCapStyle: 'butt',
|
||||
@@ -129,7 +131,7 @@ onMounted(() => {
|
||||
{
|
||||
label: 'Expenses',
|
||||
fill: false,
|
||||
lineTension: 0.3,
|
||||
tension: 0.3,
|
||||
backgroundColor: 'rgba(245, 235, 242)',
|
||||
borderColor: 'rgb(255,0,0)',
|
||||
borderCapStyle: 'butt',
|
||||
@@ -150,7 +152,7 @@ onMounted(() => {
|
||||
{
|
||||
label: 'Net Income',
|
||||
fill: false,
|
||||
lineTension: 0.3,
|
||||
tension: 0.3,
|
||||
backgroundColor: 'rgba(236, 235, 249)',
|
||||
borderColor: 'rgba(88, 81, 216, 1)',
|
||||
borderCapStyle: 'butt',
|
||||
@@ -190,8 +192,6 @@ function update() {
|
||||
(expense) => expense / 100
|
||||
)
|
||||
myLineChart.data.datasets[3].data = props.income.map((_i) => _i / 100)
|
||||
myLineChart.update({
|
||||
lazy: true,
|
||||
})
|
||||
myLineChart.update('none')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
}}
|
||||
</p>
|
||||
|
||||
<form action="" @submit.prevent="submitBulkUpdate">
|
||||
<form id="bulk-update-form" action="" @submit.prevent="submitBulkUpdate">
|
||||
<ValidateEach
|
||||
v-for="(c, i) in exchangeRateStore.bulkCurrencies"
|
||||
:key="i"
|
||||
@@ -50,22 +50,21 @@
|
||||
</BaseInputGroup>
|
||||
</template>
|
||||
</ValidateEach>
|
||||
</form>
|
||||
|
||||
<template #footer>
|
||||
<div
|
||||
slot="footer"
|
||||
class="
|
||||
z-0
|
||||
flex
|
||||
justify-end
|
||||
mt-4
|
||||
pt-4
|
||||
border-t border-gray-200 border-solid border-modal-bg
|
||||
"
|
||||
>
|
||||
<BaseButton :loading="isSaving" variant="primary" type="submit">
|
||||
<BaseButton :loading="isSaving" variant="primary" type="submit" form="bulk-update-form">
|
||||
{{ $t('general.save') }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
</BaseCard>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<BaseContentPlaceholders v-if="loading">
|
||||
<BaseContentPlaceholdersText
|
||||
:lines="1"
|
||||
class="w-24 h-8 border rounded-md"
|
||||
class="w-24 h-8 border border-gray-200 rounded-md"
|
||||
/>
|
||||
</BaseContentPlaceholders>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<template v-if="userStore.hasAbilities(ability)" #action>
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center w-full px-2 py-2 bg-gray-200 border-none outline-none cursor-pointer "
|
||||
class="flex items-center justify-center w-full px-2 py-2 bg-gray-200 border-none outline-hidden cursor-pointer "
|
||||
@click="openTaxModal"
|
||||
>
|
||||
<BaseIcon name="CheckCircleIcon" class="h-5 text-primary-400" />
|
||||
@@ -106,7 +106,7 @@ const props = defineProps({
|
||||
},
|
||||
taxes: {
|
||||
type: Array,
|
||||
default: [],
|
||||
default: () => [],
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<BaseContentPlaceholders v-if="isLoading">
|
||||
<BaseContentPlaceholdersText
|
||||
:lines="1"
|
||||
class="w-24 h-8 border rounded-md"
|
||||
class="w-24 h-8 border border-gray-200 rounded-md"
|
||||
/>
|
||||
</BaseContentPlaceholders>
|
||||
<div v-else class="flex" style="width: 140px" role="group">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<BaseIcon
|
||||
v-tooltip="{ content: 'Fetch Latest Exchange rate' }"
|
||||
name="ArrowPathIcon"
|
||||
:class="`h-4 w-4 text-primary-500 cursor-pointer outline-none ${
|
||||
:class="`h-4 w-4 text-primary-500 cursor-pointer outline-hidden ${
|
||||
isFetching
|
||||
? ' animate-spin rotate-180 cursor-not-allowed pointer-events-none '
|
||||
: ''
|
||||
|
||||
@@ -79,6 +79,7 @@ const addressData = computed(() => {
|
||||
address: pick(address, ['address_street_1', 'city', 'state', 'zip']),
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
const isAddressAvailable = computed(() => {
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<div class="w-full mt-4 tax-select">
|
||||
<Popover v-slot="{ isOpen }" class="relative">
|
||||
<PopoverButton
|
||||
:class="isOpen ? '' : 'text-opacity-90'"
|
||||
:class="isOpen ? '' : ''"
|
||||
class="
|
||||
flex
|
||||
items-center
|
||||
text-sm
|
||||
font-medium
|
||||
text-primary-400
|
||||
focus:outline-none focus:border-none
|
||||
focus:outline-hidden focus:border-none
|
||||
"
|
||||
>
|
||||
<BaseIcon
|
||||
@@ -39,7 +39,7 @@
|
||||
overflow-hidden
|
||||
rounded-md
|
||||
shadow-lg
|
||||
ring-1 ring-black ring-opacity-5
|
||||
ring-1 ring-black/5
|
||||
"
|
||||
>
|
||||
<!-- Tax Search Input -->
|
||||
@@ -142,7 +142,7 @@
|
||||
py-3
|
||||
bg-gray-200
|
||||
border-none
|
||||
outline-none
|
||||
outline-hidden
|
||||
"
|
||||
@click="openTaxTypeModal"
|
||||
>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
flex
|
||||
justify-end
|
||||
p-4
|
||||
border-t border-gray-200 border-solid border-modal-bg
|
||||
border-t border-gray-200 border-solid
|
||||
"
|
||||
>
|
||||
<BaseButton
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
</BaseInputGrid>
|
||||
</div>
|
||||
|
||||
<div class="z-0 flex justify-end p-4 bg-gray-50 border-modal-bg">
|
||||
<div class="z-0 flex justify-end p-4 bg-gray-50 border-t border-gray-200">
|
||||
<BaseButton
|
||||
class="mr-3 text-sm"
|
||||
variant="primary-outline"
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</BaseInputGroup>
|
||||
</div>
|
||||
|
||||
<div class="z-0 flex justify-end p-4 bg-gray-50 border-modal-bg">
|
||||
<div class="z-0 flex justify-end p-4 bg-gray-50 border-t border-gray-200">
|
||||
<BaseButton
|
||||
class="mr-3 text-sm"
|
||||
variant="primary-outline"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
>
|
||||
<template #default="slotProps">
|
||||
<div
|
||||
class="z-0 flex justify-end p-4 border-t border-solid border-gray-light"
|
||||
class="z-0 flex justify-end p-4 border-t border-solid border-gray-200"
|
||||
>
|
||||
<BaseButton
|
||||
class="mr-3 text-sm"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
flex
|
||||
justify-end
|
||||
p-4
|
||||
border-t border-gray-200 border-solid border-modal-bg
|
||||
border-t border-gray-200 border-solid
|
||||
"
|
||||
>
|
||||
<BaseButton
|
||||
|
||||
@@ -75,7 +75,7 @@ _ />
|
||||
justify-end
|
||||
px-4
|
||||
py-4
|
||||
border-t border-solid border-gray-light
|
||||
border-t border-solid border-gray-200
|
||||
"
|
||||
>
|
||||
<BaseButton
|
||||
@@ -280,7 +280,7 @@ function closeNoteModal() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style>
|
||||
.note-modal {
|
||||
.header-editior .editor-menu-bar {
|
||||
margin-left: 0.5px;
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
flex
|
||||
justify-end
|
||||
p-4
|
||||
border-t border-solid border--200 border-modal-bg
|
||||
border-t border-solid border-gray-200
|
||||
"
|
||||
>
|
||||
<BaseButton
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
flex
|
||||
justify-end
|
||||
p-4
|
||||
border-t border-solid border--200 border-modal-bg
|
||||
border-t border-solid border-gray-200
|
||||
"
|
||||
>
|
||||
<BaseButton
|
||||
|
||||
@@ -116,7 +116,6 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import axios from 'axios'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
flex
|
||||
justify-end
|
||||
p-4
|
||||
border-t border-solid border-gray-light border-modal-bg
|
||||
border-t border-solid border-gray-200
|
||||
"
|
||||
>
|
||||
<BaseButton
|
||||
|
||||
@@ -168,5 +168,5 @@ const loginPageLogo = computed(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
px-4
|
||||
py-3
|
||||
md:h-16 md:px-8
|
||||
bg-gradient-to-r
|
||||
bg-linear-to-r
|
||||
from-primary-500
|
||||
to-primary-400
|
||||
"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
leave-from="opacity-100"
|
||||
leave-to="opacity-0"
|
||||
>
|
||||
<DialogOverlay class="fixed inset-0 bg-gray-600 bg-opacity-75" />
|
||||
<DialogOverlay class="fixed inset-0 bg-gray-600/75" />
|
||||
</TransitionChild>
|
||||
|
||||
<TransitionChild
|
||||
@@ -47,7 +47,7 @@
|
||||
h-10
|
||||
ml-1
|
||||
rounded-full
|
||||
focus:outline-none
|
||||
focus:outline-hidden
|
||||
focus:ring-2
|
||||
focus:ring-inset
|
||||
focus:ring-white
|
||||
@@ -82,9 +82,9 @@
|
||||
:to="item.link"
|
||||
:class="[
|
||||
hasActiveUrl(item.link)
|
||||
? 'text-primary-500 border-primary-500 bg-gray-100 '
|
||||
: 'text-black',
|
||||
'cursor-pointer px-0 pl-4 py-3 border-transparent flex items-center border-l-4 border-solid text-sm not-italic font-medium',
|
||||
? 'text-primary-500 border-l-primary-500 bg-gray-100 '
|
||||
: 'text-black border-l-transparent',
|
||||
'cursor-pointer px-0 pl-4 py-3 flex items-center border-l-4 border-solid text-sm not-italic font-medium',
|
||||
]"
|
||||
@click="globalStore.setSidebarVisibility(false)"
|
||||
>
|
||||
@@ -136,8 +136,8 @@
|
||||
:to="item.link"
|
||||
:class="[
|
||||
hasActiveUrl(item.link)
|
||||
? 'text-primary-500 border-primary-500 bg-gray-100 '
|
||||
: 'text-black',
|
||||
? 'text-primary-500 border-l-primary-500 bg-gray-100 '
|
||||
: 'text-black border-l-transparent',
|
||||
'cursor-pointer px-0 pl-6 hover:bg-gray-50 py-3 group flex items-center border-l-4 border-solid text-sm not-italic font-medium',
|
||||
]"
|
||||
>
|
||||
|
||||
26
resources/scripts/admin/stores/auth.js
vendored
26
resources/scripts/admin/stores/auth.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,8 +7,7 @@ export const useAuthStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'auth',
|
||||
return defineStoreFunc('auth', {
|
||||
state: () => ({
|
||||
status: '',
|
||||
|
||||
@@ -22,9 +21,9 @@ export const useAuthStore = (useWindow = false) => {
|
||||
actions: {
|
||||
login(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get('/sanctum/csrf-cookie').then((response) => {
|
||||
http.get('/sanctum/csrf-cookie').then((response) => {
|
||||
if (response) {
|
||||
axios
|
||||
http
|
||||
.post('/login', data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -45,22 +44,31 @@ export const useAuthStore = (useWindow = false) => {
|
||||
|
||||
logout() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/auth/logout')
|
||||
.then((response) => {
|
||||
.then(async (response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: 'Logged out successfully.',
|
||||
})
|
||||
|
||||
// Clear stored auth data so next login doesn't send stale tokens
|
||||
window.Ls.remove('auth.token')
|
||||
window.Ls.remove('selectedCompany')
|
||||
|
||||
// Refresh CSRF token so next login works cleanly
|
||||
await http.get('/sanctum/csrf-cookie').catch(() => {})
|
||||
|
||||
window.router.push('/login')
|
||||
// resetStore.clearPinia()
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
window.router.push('/')
|
||||
window.Ls.remove('auth.token')
|
||||
window.Ls.remove('selectedCompany')
|
||||
http.get('/sanctum/csrf-cookie').catch(() => {})
|
||||
window.router.push('/login')
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
|
||||
12
resources/scripts/admin/stores/backup.js
vendored
12
resources/scripts/admin/stores/backup.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,9 +7,7 @@ export const useBackupStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'backup',
|
||||
|
||||
return defineStoreFunc('backup', {
|
||||
state: () => ({
|
||||
backups: [],
|
||||
currentBackupData: {
|
||||
@@ -21,7 +19,7 @@ export const useBackupStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchBackups(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/backups`, { params })
|
||||
.then((response) => {
|
||||
this.backups = response.data.data
|
||||
@@ -36,7 +34,7 @@ export const useBackupStore = (useWindow = false) => {
|
||||
|
||||
createBackup(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/backups`, data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -55,7 +53,7 @@ export const useBackupStore = (useWindow = false) => {
|
||||
|
||||
removeBackup(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/backups/${params.disk}`, { params })
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
16
resources/scripts/admin/stores/category.js
vendored
16
resources/scripts/admin/stores/category.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,9 +7,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'category',
|
||||
|
||||
return defineStoreFunc('category', {
|
||||
state: () => ({
|
||||
categories: [],
|
||||
currentCategory: {
|
||||
@@ -27,7 +25,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchCategories(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/categories`, { params })
|
||||
.then((response) => {
|
||||
this.categories = response.data.data
|
||||
@@ -42,7 +40,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
|
||||
fetchCategory(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/categories/${id}`)
|
||||
.then((response) => {
|
||||
this.currentCategory = response.data.data
|
||||
@@ -57,7 +55,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
|
||||
addCategory(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/categories', data)
|
||||
.then((response) => {
|
||||
this.categories.push(response.data.data)
|
||||
@@ -77,7 +75,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
|
||||
updateCategory(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/categories/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -104,7 +102,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
|
||||
deleteCategory(id) {
|
||||
return new Promise((resolve) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/categories/${id}`)
|
||||
.then((response) => {
|
||||
let index = this.categories.findIndex(
|
||||
|
||||
24
resources/scripts/admin/stores/company.js
vendored
24
resources/scripts/admin/stores/company.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -8,9 +8,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'company',
|
||||
|
||||
return defineStoreFunc('company', {
|
||||
state: () => ({
|
||||
companies: [],
|
||||
selectedCompany: null,
|
||||
@@ -26,7 +24,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
fetchBasicMailConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/company/mail/config')
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -40,7 +38,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
updateCompany(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put('/api/v1/company', data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -66,7 +64,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
updateCompanyLogo(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/company/upload-logo', data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -80,7 +78,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
addNewCompany(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/companies', data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -99,7 +97,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
fetchCompany(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/current-company', params)
|
||||
.then((response) => {
|
||||
Object.assign(this.companyForm, response.data.data.address)
|
||||
@@ -115,7 +113,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
fetchUserCompanies() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/companies')
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -129,7 +127,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
fetchCompanySettings(settings) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/company/settings', {
|
||||
params: {
|
||||
settings,
|
||||
@@ -147,7 +145,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
updateCompanySettings({ data, message }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/company/settings', data)
|
||||
.then((response) => {
|
||||
Object.assign(this.selectedCompanySettings, data.settings)
|
||||
@@ -172,7 +170,7 @@ export const useCompanyStore = (useWindow = false) => {
|
||||
|
||||
deleteCompany(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/companies/delete`, data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
|
||||
18
resources/scripts/admin/stores/custom-field.js
vendored
18
resources/scripts/admin/stores/custom-field.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import customFieldStub from '@/scripts/admin/stub/custom-field'
|
||||
@@ -10,9 +10,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'custom-field',
|
||||
|
||||
return defineStoreFunc('custom-field', {
|
||||
state: () => ({
|
||||
customFields: [],
|
||||
isRequestOngoing: false,
|
||||
@@ -41,7 +39,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
|
||||
fetchCustomFields(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/custom-fields`, { params })
|
||||
.then((response) => {
|
||||
this.customFields = response.data.data
|
||||
@@ -63,7 +61,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
|
||||
this.isRequestOngoing = true
|
||||
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/custom-fields`, { params })
|
||||
.then((response) => {
|
||||
this.customFields = response.data.data
|
||||
@@ -80,7 +78,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
|
||||
fetchCustomField(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/custom-fields/${id}`)
|
||||
.then((response) => {
|
||||
this.currentCustomField = response.data.data
|
||||
@@ -107,7 +105,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
addCustomField(params) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/custom-fields`, params)
|
||||
.then((response) => {
|
||||
let data = {
|
||||
@@ -139,7 +137,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/custom-fields/${params.id}`, params)
|
||||
.then((response) => {
|
||||
let data = {
|
||||
@@ -174,7 +172,7 @@ export const useCustomFieldStore = (useWindow = false) => {
|
||||
deleteCustomFields(id) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/custom-fields/${id}`)
|
||||
.then((response) => {
|
||||
let index = this.customFields.findIndex(
|
||||
|
||||
19
resources/scripts/admin/stores/customer.js
vendored
19
resources/scripts/admin/stores/customer.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -12,8 +12,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'customer',
|
||||
return defineStoreFunc('customer', {
|
||||
state: () => ({
|
||||
customers: [],
|
||||
totalCustomers: 0,
|
||||
@@ -75,7 +74,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
|
||||
fetchCustomers(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/customers`, { params })
|
||||
.then((response) => {
|
||||
this.customers = response.data.data
|
||||
@@ -92,7 +91,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
fetchViewCustomer(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.isFetchingViewData = true
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/customers/${params.id}/stats`, { params })
|
||||
|
||||
.then((response) => {
|
||||
@@ -112,7 +111,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
|
||||
fetchCustomer(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/customers/${id}`)
|
||||
.then((response) => {
|
||||
Object.assign(this.currentCustomer, response.data.data)
|
||||
@@ -129,7 +128,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
|
||||
addCustomer(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/customers', data)
|
||||
.then((response) => {
|
||||
this.customers.push(response.data.data)
|
||||
@@ -151,7 +150,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
|
||||
updateCustomer(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/customers/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -177,7 +176,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
deleteCustomer(id) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/customers/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.customers.findIndex(
|
||||
@@ -201,7 +200,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/customers/delete`, { ids: this.selectedCustomers })
|
||||
.then((response) => {
|
||||
this.selectedCustomers.forEach((customer) => {
|
||||
|
||||
8
resources/scripts/admin/stores/dashboard.js
vendored
8
resources/scripts/admin/stores/dashboard.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,9 +7,7 @@ export const useDashboardStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'dashboard',
|
||||
|
||||
return defineStoreFunc('dashboard', {
|
||||
state: () => ({
|
||||
stats: {
|
||||
totalAmountDue: 0,
|
||||
@@ -40,7 +38,7 @@ export const useDashboardStore = (useWindow = false) => {
|
||||
actions: {
|
||||
loadData(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/dashboard`, { params })
|
||||
.then((response) => {
|
||||
// Stats
|
||||
|
||||
18
resources/scripts/admin/stores/disk.js
vendored
18
resources/scripts/admin/stores/disk.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,9 +7,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'disk',
|
||||
|
||||
return defineStoreFunc('disk', {
|
||||
state: () => ({
|
||||
disks: [],
|
||||
diskDrivers: [],
|
||||
@@ -71,7 +69,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchDiskEnv(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/disks/${data.disk}`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -85,7 +83,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
|
||||
fetchDisks(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/disks`, { params })
|
||||
.then((response) => {
|
||||
this.disks = response.data.data
|
||||
@@ -100,7 +98,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
|
||||
fetchDiskDrivers() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/disk/drivers`)
|
||||
.then((response) => {
|
||||
this.diskConfigData = response.data
|
||||
@@ -116,7 +114,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
|
||||
deleteFileDisk(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/disks/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data.success) {
|
||||
@@ -141,7 +139,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
|
||||
updateDisk(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/disks/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -166,7 +164,7 @@ export const useDiskStore = (useWindow = false) => {
|
||||
|
||||
createDisk(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/disks`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
|
||||
40
resources/scripts/admin/stores/estimate.js
vendored
40
resources/scripts/admin/stores/estimate.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import moment from 'moment'
|
||||
import Guid from 'guid'
|
||||
import _ from 'lodash'
|
||||
@@ -20,9 +20,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'estimate',
|
||||
|
||||
return defineStoreFunc('estimate', {
|
||||
state: () => ({
|
||||
templates: [],
|
||||
|
||||
@@ -100,7 +98,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
previewEstimate(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/estimates/${params.id}/send/preview`, { params })
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -114,7 +112,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
fetchEstimates(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/estimates`, { params })
|
||||
.then((response) => {
|
||||
this.estimates = response.data.data
|
||||
@@ -130,7 +128,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
getNextNumber(params, setState = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/next-number?key=estimate`, { params })
|
||||
.then((response) => {
|
||||
if (setState) {
|
||||
@@ -147,7 +145,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
fetchEstimate(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/estimates/${id}`)
|
||||
.then((response) => {
|
||||
this.setEstimateData(response.data.data)
|
||||
@@ -222,7 +220,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/${data.id}/send`, data)
|
||||
.then((response) => {
|
||||
if (!data.is_preview) {
|
||||
@@ -242,7 +240,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
addEstimate(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/estimates', data)
|
||||
.then((response) => {
|
||||
this.estimates = [...this.estimates, response.data.estimate]
|
||||
@@ -266,7 +264,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.estimates.findIndex(
|
||||
@@ -292,7 +290,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/delete`, { ids: this.selectedEstimates })
|
||||
.then((response) => {
|
||||
this.selectedEstimates.forEach((estimate) => {
|
||||
@@ -318,7 +316,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
updateEstimate(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/estimates/${data.id}`, data)
|
||||
.then((response) => {
|
||||
let pos = this.estimates.findIndex(
|
||||
@@ -341,7 +339,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
cloneEstimate(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/${data.id}/clone`, data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -360,7 +358,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
markAsAccepted(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/${data.id}/status`, data)
|
||||
.then((response) => {
|
||||
let pos = this.estimates.findIndex(
|
||||
@@ -387,7 +385,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
markAsRejected(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/${data.id}/status`, data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -407,7 +405,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
markAsSent(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/${data.id}/status`, data)
|
||||
.then((response) => {
|
||||
let pos = this.estimates.findIndex(
|
||||
@@ -435,7 +433,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
convertToInvoice(id) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/estimates/${id}/convert-to-invoice`)
|
||||
.then((response) => {
|
||||
notificationStore.showNotification({
|
||||
@@ -453,7 +451,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
searchEstimate(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/estimates?${data}`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -487,7 +485,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
|
||||
selectCustomer(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/customers/${id}`)
|
||||
.then((response) => {
|
||||
this.newEstimate.customer = response.data.data
|
||||
@@ -502,7 +500,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
},
|
||||
fetchEstimateTemplates(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/estimates/templates`, { params })
|
||||
.then((response) => {
|
||||
this.templates = response.data.estimateTemplates
|
||||
|
||||
32
resources/scripts/admin/stores/exchange-rate.js
vendored
32
resources/scripts/admin/stores/exchange-rate.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -8,9 +8,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
const { global } = window.i18n
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'exchange-rate',
|
||||
|
||||
return defineStoreFunc('exchange-rate', {
|
||||
state: () => ({
|
||||
supportedCurrencies: [],
|
||||
drivers: [],
|
||||
@@ -37,7 +35,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchProviders(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/exchange-rate-providers', { params })
|
||||
.then((response) => {
|
||||
this.providers = response.data.data
|
||||
@@ -52,7 +50,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
|
||||
fetchDefaultProviders() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/config?key=exchange_rate_drivers`)
|
||||
.then((response) => {
|
||||
this.drivers = response.data.exchange_rate_drivers
|
||||
@@ -68,7 +66,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
|
||||
fetchProvider(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/exchange-rate-providers/${id}`)
|
||||
.then((response) => {
|
||||
this.currentExchangeRate = response.data.data
|
||||
@@ -84,7 +82,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
|
||||
addProvider(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/exchange-rate-providers', data)
|
||||
.then((response) => {
|
||||
notificationStore.showNotification({
|
||||
@@ -104,7 +102,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
|
||||
updateProvider(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/exchange-rate-providers/${data.id}`, data)
|
||||
.then((response) => {
|
||||
notificationStore.showNotification({
|
||||
@@ -122,7 +120,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
|
||||
deleteExchangeRate(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/exchange-rate-providers/${id}`)
|
||||
.then((response) => {
|
||||
let index = this.drivers.findIndex((driver) => driver.id === id)
|
||||
@@ -148,7 +146,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
fetchCurrencies(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/supported-currencies`, { params })
|
||||
.then((response) => {
|
||||
this.supportedCurrencies = response.data.supportedCurrencies
|
||||
@@ -163,7 +161,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
fetchActiveCurrency(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/used-currencies', { params })
|
||||
.then((response) => {
|
||||
this.activeUsedCurrencies = response.data.activeUsedCurrencies
|
||||
@@ -178,7 +176,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
fetchBulkCurrencies() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/currencies/used')
|
||||
.then((response) => {
|
||||
this.bulkCurrencies = response.data.currencies.map((_m) => {
|
||||
@@ -196,7 +194,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
updateBulkExchangeRate(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/currencies/bulk-update-exchange-rate', data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -209,7 +207,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
getCurrentExchangeRate(currencyId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/currencies/${currencyId}/exchange-rate`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -221,7 +219,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
getCurrencyConverterServers() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/config?key=currency_converter_servers')
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -234,7 +232,7 @@ export const useExchangeRateStore = (useWindow = false) => {
|
||||
},
|
||||
checkForActiveProvider(currency_id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/currencies/${currency_id}/active-provider`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
|
||||
20
resources/scripts/admin/stores/expense.js
vendored
20
resources/scripts/admin/stores/expense.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
@@ -9,9 +9,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'expense',
|
||||
|
||||
return defineStoreFunc('expense', {
|
||||
state: () => ({
|
||||
expenses: [],
|
||||
totalExpenses: 0,
|
||||
@@ -38,7 +36,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
|
||||
fetchExpenses(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/expenses`, { params })
|
||||
.then((response) => {
|
||||
this.expenses = response.data.data
|
||||
@@ -54,7 +52,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
|
||||
fetchExpense(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/expenses/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -97,7 +95,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
const formData = utils.toFormData(data)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/expenses', formData)
|
||||
.then((response) => {
|
||||
this.expenses.push(response.data)
|
||||
@@ -127,7 +125,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
formData.append('is_attachment_receipt_removed', isAttachmentReceiptRemoved)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
axios.post(`/api/v1/expenses/${id}`, formData).then((response) => {
|
||||
http.post(`/api/v1/expenses/${id}`, formData).then((response) => {
|
||||
let pos = this.expenses.findIndex(
|
||||
(expense) => expense.id === response.data.id
|
||||
)
|
||||
@@ -175,7 +173,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/expenses/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.expenses.findIndex(
|
||||
@@ -200,7 +198,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/expenses/delete`, { ids: this.selectedExpenses })
|
||||
.then((response) => {
|
||||
this.selectedExpenses.forEach((expense) => {
|
||||
@@ -223,7 +221,7 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
},
|
||||
fetchPaymentModes(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payment-methods`, { params })
|
||||
.then((response) => {
|
||||
this.paymentModes = response.data.data
|
||||
|
||||
23
resources/scripts/admin/stores/global.js
vendored
23
resources/scripts/admin/stores/global.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useCompanyStore } from './company'
|
||||
import { useUserStore } from './user'
|
||||
@@ -11,8 +11,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'global',
|
||||
return defineStoreFunc('global', {
|
||||
state: () => ({
|
||||
// Global Configuration
|
||||
config: null,
|
||||
@@ -48,7 +47,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
actions: {
|
||||
bootstrap() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/bootstrap')
|
||||
.then(async (response) => {
|
||||
const companyStore = useCompanyStore()
|
||||
@@ -123,7 +122,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
resolve(this.currencies)
|
||||
} else {
|
||||
this.areCurrenciesLoading = true
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/currencies')
|
||||
.then((response) => {
|
||||
this.currencies = response.data.data.filter((currency) => {
|
||||
@@ -143,7 +142,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
|
||||
fetchConfig(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/config`, { params })
|
||||
.then((response) => {
|
||||
if (response.data.languages) {
|
||||
@@ -165,7 +164,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
if (this.dateFormats.length) {
|
||||
resolve(this.dateFormats)
|
||||
} else {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/date/formats')
|
||||
.then((response) => {
|
||||
this.dateFormats = response.data.date_formats
|
||||
@@ -184,7 +183,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
if (this.timeFormats.length) {
|
||||
resolve(this.timeFormats)
|
||||
} else {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/time/formats')
|
||||
.then((response) => {
|
||||
this.timeFormats = response.data.time_formats
|
||||
@@ -203,7 +202,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
if (this.timeZones.length) {
|
||||
resolve(this.timeZones)
|
||||
} else {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/timezones')
|
||||
.then((response) => {
|
||||
this.timeZones = response.data.time_zones
|
||||
@@ -222,7 +221,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
if (this.countries.length) {
|
||||
resolve(this.countries)
|
||||
} else {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/countries')
|
||||
.then((response) => {
|
||||
this.countries = response.data.data
|
||||
@@ -238,7 +237,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
|
||||
fetchPlaceholders(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/number-placeholders`, { params })
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -260,7 +259,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
|
||||
updateGlobalSettings({ data, message }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/settings', data)
|
||||
.then((response) => {
|
||||
Object.assign(this.globalSettings, data.settings)
|
||||
|
||||
32
resources/scripts/admin/stores/installation.js
vendored
32
resources/scripts/admin/stores/installation.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useCompanyStore } from './company'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -8,9 +8,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
const { global } = window.i18n
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'installation',
|
||||
|
||||
return defineStoreFunc('installation', {
|
||||
state: () => ({
|
||||
currentDataBaseData: {
|
||||
database_connection: 'mysql',
|
||||
@@ -28,7 +26,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchInstallationLanguages() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/installation/languages`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -42,7 +40,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
fetchInstallationRequirements() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/installation/requirements`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -56,7 +54,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
fetchInstallationStep() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/installation/wizard-step`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -70,7 +68,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
addInstallationStep(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/installation/wizard-step`, data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -84,7 +82,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
addInstallationLanguage(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/installation/wizard-language`, data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -98,7 +96,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
fetchInstallationPermissions() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/installation/permissions`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -112,7 +110,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
fetchInstallationDatabase(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/installation/database/config`, { params })
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -126,7 +124,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
addInstallationDatabase(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/installation/database/config`, data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -140,7 +138,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
addInstallationFinish() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/installation/finish`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -154,7 +152,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
setInstallationDomain(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/installation/set-domain`, data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -168,9 +166,9 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
installationLogin() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get('/sanctum/csrf-cookie').then((response) => {
|
||||
http.get('/sanctum/csrf-cookie').then((response) => {
|
||||
if (response) {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/installation/login')
|
||||
.then((response) => {
|
||||
companyStore.setSelectedCompany(response.data.company)
|
||||
@@ -187,7 +185,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
|
||||
checkAuthenticated() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/auth/check`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
|
||||
33
resources/scripts/admin/stores/invoice.js
vendored
33
resources/scripts/admin/stores/invoice.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import moment from 'moment'
|
||||
import Guid from 'guid'
|
||||
import _ from 'lodash'
|
||||
@@ -22,8 +22,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
const { global } = window.i18n
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'invoice',
|
||||
return defineStoreFunc('invoice', {
|
||||
state: () => ({
|
||||
templates: [],
|
||||
invoices: [],
|
||||
@@ -108,7 +107,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
previewInvoice(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/invoices/${params.id}/send/preview`, { params })
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -122,7 +121,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
fetchInvoices(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/invoices`, { params })
|
||||
.then((response) => {
|
||||
this.invoices = response.data.data
|
||||
@@ -138,7 +137,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
fetchInvoice(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/invoices/${id}`)
|
||||
.then((response) => {
|
||||
this.setInvoiceData(response.data.data)
|
||||
@@ -204,7 +203,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
sendInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/invoices/${data.id}/send`, data)
|
||||
.then((response) => {
|
||||
notificationStore.showNotification({
|
||||
@@ -222,7 +221,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
addInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/invoices', data)
|
||||
.then((response) => {
|
||||
this.invoices = [...this.invoices, response.data.invoice]
|
||||
@@ -243,7 +242,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
deleteInvoice(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/invoices/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.invoices.findIndex(
|
||||
@@ -266,7 +265,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
deleteMultipleInvoices(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/invoices/delete`, { ids: this.selectedInvoices })
|
||||
.then((response) => {
|
||||
this.selectedInvoices.forEach((invoice) => {
|
||||
@@ -292,7 +291,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
updateInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/invoices/${data.id}`, data)
|
||||
.then((response) => {
|
||||
let pos = this.invoices.findIndex(
|
||||
@@ -316,7 +315,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
cloneInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/invoices/${data.id}/clone`, data)
|
||||
.then((response) => {
|
||||
notificationStore.showNotification({
|
||||
@@ -334,7 +333,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
markAsSent(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/invoices/${data.id}/status`, data)
|
||||
.then((response) => {
|
||||
let pos = this.invoices.findIndex(
|
||||
@@ -360,7 +359,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
getNextNumber(params, setState = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/next-number?key=invoice`, { params })
|
||||
.then((response) => {
|
||||
if (setState) {
|
||||
@@ -377,7 +376,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
searchInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/invoices?${data}`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -411,7 +410,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
selectCustomer(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/customers/${id}`)
|
||||
.then((response) => {
|
||||
this.newInvoice.customer = response.data.data
|
||||
@@ -427,7 +426,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
fetchInvoiceTemplates(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/invoices/templates`, { params })
|
||||
.then((response) => {
|
||||
this.templates = response.data.invoiceTemplates
|
||||
|
||||
27
resources/scripts/admin/stores/item.js
vendored
27
resources/scripts/admin/stores/item.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,8 +7,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'item',
|
||||
return defineStoreFunc('item', {
|
||||
state: () => ({
|
||||
items: [],
|
||||
totalItems: 0,
|
||||
@@ -45,7 +44,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
},
|
||||
fetchItems(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/items`, { params })
|
||||
.then((response) => {
|
||||
this.items = response.data.data
|
||||
@@ -62,7 +61,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
|
||||
fetchItem(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/items/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -79,7 +78,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
|
||||
addItem(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/items', data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -102,7 +101,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
|
||||
updateItem(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/items/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -133,7 +132,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/items/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.items.findIndex((item) => item.id === id)
|
||||
@@ -157,7 +156,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/items/delete`, { ids: this.selectedItems })
|
||||
.then((response) => {
|
||||
this.selectedItems.forEach((item) => {
|
||||
@@ -205,7 +204,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/units`, data)
|
||||
.then((response) => {
|
||||
this.itemUnits.push(response.data.data)
|
||||
@@ -239,7 +238,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/units/${data.id}`, data)
|
||||
.then((response) => {
|
||||
let pos = this.itemUnits.findIndex(
|
||||
@@ -274,7 +273,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
|
||||
fetchItemUnits(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/units`, { params })
|
||||
.then((response) => {
|
||||
this.itemUnits = response.data.data
|
||||
@@ -289,7 +288,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
|
||||
fetchItemUnit(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/units/${id}`)
|
||||
.then((response) => {
|
||||
this.currentItemUnit = response.data.data
|
||||
@@ -306,7 +305,7 @@ export const useItemStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/units/${id}`)
|
||||
.then((response) => {
|
||||
if (!response.data.error) {
|
||||
|
||||
14
resources/scripts/admin/stores/mail-driver.js
vendored
14
resources/scripts/admin/stores/mail-driver.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,9 +7,7 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'mail-driver',
|
||||
|
||||
return defineStoreFunc('mail-driver', {
|
||||
state: () => ({
|
||||
mailConfigData: null,
|
||||
mail_driver: 'smtp',
|
||||
@@ -57,7 +55,7 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchMailDrivers() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/mail/drivers')
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -74,7 +72,7 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
|
||||
fetchMailConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/mail/config')
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -92,7 +90,7 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
|
||||
updateMailConfig(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/mail/config', data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -118,7 +116,7 @@ export const useMailDriverStore = (useWindow = false) => {
|
||||
|
||||
sendTestMail(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/mail/test', data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
16
resources/scripts/admin/stores/module.js
vendored
16
resources/scripts/admin/stores/module.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
@@ -7,9 +7,7 @@ export const useModuleStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'modules',
|
||||
|
||||
return defineStoreFunc('modules', {
|
||||
state: () => ({
|
||||
currentModule: {},
|
||||
modules: [],
|
||||
@@ -27,7 +25,7 @@ export const useModuleStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchModules(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/modules`)
|
||||
.then((response) => {
|
||||
this.modules = response.data.data
|
||||
@@ -43,7 +41,7 @@ export const useModuleStore = (useWindow = false) => {
|
||||
|
||||
fetchModule(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/modules/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data.error === 'invalid_token') {
|
||||
@@ -67,7 +65,7 @@ export const useModuleStore = (useWindow = false) => {
|
||||
|
||||
checkApiToken(token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/modules/check?api_token=${token}`)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -88,7 +86,7 @@ export const useModuleStore = (useWindow = false) => {
|
||||
|
||||
disableModule(module) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/modules/${module}/disable`)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -109,7 +107,7 @@ export const useModuleStore = (useWindow = false) => {
|
||||
|
||||
enableModule(module) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/modules/${module}/enable`)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
16
resources/scripts/admin/stores/note.js
vendored
16
resources/scripts/admin/stores/note.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
@@ -6,9 +6,7 @@ export const useNotesStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'notes',
|
||||
|
||||
return defineStoreFunc('notes', {
|
||||
state: () => ({
|
||||
notes: [],
|
||||
currentNote: {
|
||||
@@ -40,7 +38,7 @@ export const useNotesStore = (useWindow = false) => {
|
||||
|
||||
fetchNotes(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/notes`, { params })
|
||||
.then((response) => {
|
||||
this.notes = response.data.data
|
||||
@@ -55,7 +53,7 @@ export const useNotesStore = (useWindow = false) => {
|
||||
|
||||
fetchNote(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/notes/${id}`)
|
||||
.then((response) => {
|
||||
this.currentNote = response.data.data
|
||||
@@ -70,7 +68,7 @@ export const useNotesStore = (useWindow = false) => {
|
||||
|
||||
addNote(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/notes', data)
|
||||
.then((response) => {
|
||||
this.notes.push(response.data)
|
||||
@@ -85,7 +83,7 @@ export const useNotesStore = (useWindow = false) => {
|
||||
|
||||
updateNote(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/notes/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -105,7 +103,7 @@ export const useNotesStore = (useWindow = false) => {
|
||||
|
||||
deleteNote(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/notes/${id}`)
|
||||
.then((response) => {
|
||||
let index = this.notes.findIndex((note) => note.id === id)
|
||||
|
||||
36
resources/scripts/admin/stores/payment.js
vendored
36
resources/scripts/admin/stores/payment.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import moment from 'moment'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useRoute } from 'vue-router'
|
||||
@@ -12,9 +12,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'payment',
|
||||
|
||||
return defineStoreFunc('payment', {
|
||||
state: () => ({
|
||||
payments: [],
|
||||
paymentTotalCount: 0,
|
||||
@@ -99,7 +97,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
fetchPayments(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payments`, { params })
|
||||
.then((response) => {
|
||||
this.payments = response.data.data
|
||||
@@ -115,7 +113,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
fetchPayment(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payments/${id}`)
|
||||
.then((response) => {
|
||||
Object.assign(this.currentPayment, response.data.data)
|
||||
@@ -130,7 +128,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
addPayment(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/payments', data)
|
||||
.then((response) => {
|
||||
this.payments.push(response.data)
|
||||
@@ -150,7 +148,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
updatePayment(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/payments/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -179,7 +177,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/payments/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.payments.findIndex(
|
||||
@@ -203,7 +201,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
deleteMultiplePayments() {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/payments/delete`, { ids: this.selectedPayments })
|
||||
.then((response) => {
|
||||
this.selectedPayments.forEach((payment) => {
|
||||
@@ -260,7 +258,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
searchPayment(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payments`, { params })
|
||||
.then((response) => {
|
||||
this.payments = response.data
|
||||
@@ -275,7 +273,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
previewPayment(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payments/${params.id}/send/preview`, { params })
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -289,7 +287,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
sendEmail(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/payments/${data.id}/send`, data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
@@ -308,7 +306,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
getNextNumber(params, setState = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/next-number?key=payment`, { params })
|
||||
.then((response) => {
|
||||
if (setState) {
|
||||
@@ -331,7 +329,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
fetchPaymentModes(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payment-methods`, { params })
|
||||
.then((response) => {
|
||||
this.paymentModes = response.data.data
|
||||
@@ -346,7 +344,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
fetchPaymentMode(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/payment-methods/${id}`)
|
||||
.then((response) => {
|
||||
this.currentPaymentMode = response.data.data
|
||||
@@ -362,7 +360,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
addPaymentMode(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/payment-methods`, data)
|
||||
.then((response) => {
|
||||
this.paymentModes.push(response.data.data)
|
||||
@@ -382,7 +380,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
updatePaymentMode(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/payment-methods/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -410,7 +408,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/payment-methods/${id}`)
|
||||
.then((response) => {
|
||||
let index = this.paymentModes.findIndex(
|
||||
|
||||
12
resources/scripts/admin/stores/pdf-driver.js
vendored
12
resources/scripts/admin/stores/pdf-driver.js
vendored
@@ -1,15 +1,13 @@
|
||||
const { defineStore } = window.pinia
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
|
||||
export const usePDFDriverStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'pdf-driver',
|
||||
|
||||
return defineStoreFunc('pdf-driver', {
|
||||
state: () => ({
|
||||
pdfDriverConfig: null,
|
||||
pdf_driver: 'dompdf',
|
||||
@@ -28,7 +26,7 @@ export const usePDFDriverStore = (useWindow = false) => {
|
||||
actions: {
|
||||
async fetchDrivers() {
|
||||
try {
|
||||
const response = await axios.get('/api/v1/pdf/drivers')
|
||||
const response = await http.get('/api/v1/pdf/drivers')
|
||||
this.pdf_drivers = response.data
|
||||
} catch (err) {
|
||||
handleError(err)
|
||||
@@ -37,7 +35,7 @@ export const usePDFDriverStore = (useWindow = false) => {
|
||||
},
|
||||
async fetchConfig() {
|
||||
try {
|
||||
const response = await axios.get('/api/v1/pdf/config')
|
||||
const response = await http.get('/api/v1/pdf/config')
|
||||
this.pdfDriverConfig = response.data
|
||||
this.pdf_driver = response.data.pdf_driver
|
||||
} catch (err) {
|
||||
@@ -47,7 +45,7 @@ export const usePDFDriverStore = (useWindow = false) => {
|
||||
},
|
||||
async updateConfig(data) {
|
||||
try {
|
||||
const response = await axios.post('/api/v1/pdf/config', data)
|
||||
const response = await http.post('/api/v1/pdf/config', data)
|
||||
const notificationStore = useNotificationStore()
|
||||
if (response.data.success) {
|
||||
notificationStore.showNotification({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import recurringInvoiceStub from '@/scripts/admin/stub/recurring-invoice'
|
||||
import recurringInvoiceItemStub from '@/scripts/admin/stub/recurring-invoice-item'
|
||||
import TaxStub from '../stub/tax'
|
||||
@@ -20,9 +20,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'recurring-invoice',
|
||||
|
||||
return defineStoreFunc('recurring-invoice', {
|
||||
state: () => ({
|
||||
templates: [],
|
||||
recurringInvoices: [],
|
||||
@@ -162,7 +160,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
addRecurringInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/recurring-invoices', data)
|
||||
.then((response) => {
|
||||
this.recurringInvoices = [
|
||||
@@ -187,7 +185,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
fetchRecurringInvoice(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.isFetchingViewData = true
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/recurring-invoices/${id}`)
|
||||
.then((response) => {
|
||||
Object.assign(this.newRecurringInvoice, response.data.data)
|
||||
@@ -207,7 +205,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
updateRecurringInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/recurring-invoices/${data.id}`, data)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -234,7 +232,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
selectCustomer(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/customers/${id}`)
|
||||
.then((response) => {
|
||||
this.newRecurringInvoice.customer = response.data.data
|
||||
@@ -250,7 +248,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
searchRecurringInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/recurring-invoices?${data}`)
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
@@ -264,7 +262,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
fetchRecurringInvoices(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/recurring-invoices`, { params })
|
||||
.then((response) => {
|
||||
this.recurringInvoices = response.data.data
|
||||
@@ -282,7 +280,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
deleteRecurringInvoice(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/recurring-invoices/delete`, id)
|
||||
.then((response) => {
|
||||
let index = this.recurringInvoices.findIndex(
|
||||
@@ -304,7 +302,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
if (id) {
|
||||
ids = [id]
|
||||
}
|
||||
axios
|
||||
http
|
||||
.post(`/api/v1/recurring-invoices/delete`, {
|
||||
ids: ids,
|
||||
})
|
||||
@@ -492,7 +490,7 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
fetchRecurringInvoiceFrequencyDate(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get('/api/v1/recurring-invoice-frequency', { params })
|
||||
.then((response) => {
|
||||
this.newRecurringInvoice.next_invoice_at =
|
||||
|
||||
4
resources/scripts/admin/stores/reset.js
vendored
4
resources/scripts/admin/stores/reset.js
vendored
@@ -1,4 +1,3 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useBackupStore } from './backup'
|
||||
import { useCategoryStore } from './category'
|
||||
@@ -30,8 +29,7 @@ export const useResetStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'reset',
|
||||
return defineStoreFunc('reset', {
|
||||
actions: {
|
||||
clearPinia() {
|
||||
const backupStore = useBackupStore()
|
||||
|
||||
17
resources/scripts/admin/stores/role.js
vendored
17
resources/scripts/admin/stores/role.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import _ from 'lodash'
|
||||
@@ -8,8 +8,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'role',
|
||||
return defineStoreFunc('role', {
|
||||
state: () => ({
|
||||
roles: [],
|
||||
allAbilities: [],
|
||||
@@ -38,7 +37,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
actions: {
|
||||
fetchRoles(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/roles`, { params })
|
||||
.then((response) => {
|
||||
this.roles = response.data.data
|
||||
@@ -53,7 +52,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
|
||||
fetchRole(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/roles/${id}`)
|
||||
.then((response) => {
|
||||
this.currentRole.name = response.data.data.name
|
||||
@@ -81,7 +80,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
addRole(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/roles', data)
|
||||
.then((response) => {
|
||||
this.roles.push(response.data.role)
|
||||
@@ -101,7 +100,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
updateRole(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/roles/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -128,7 +127,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
if (this.allAbilities.length) {
|
||||
resolve(this.allAbilities)
|
||||
} else {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/abilities`, { params })
|
||||
.then((response) => {
|
||||
this.allAbilities = response.data.abilities
|
||||
@@ -146,7 +145,7 @@ export const useRoleStore = (useWindow = false) => {
|
||||
deleteRole(id) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/roles/${id}`)
|
||||
.then((response) => {
|
||||
let index = this.roles.findIndex((role) => role.id === id)
|
||||
|
||||
18
resources/scripts/admin/stores/tax-type.js
vendored
18
resources/scripts/admin/stores/tax-type.js
vendored
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios'
|
||||
import http from '@/scripts/http'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@@ -7,9 +7,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'taxType',
|
||||
|
||||
return defineStoreFunc('taxType', {
|
||||
state: () => ({
|
||||
taxTypes: [],
|
||||
currentTaxType: {
|
||||
@@ -44,7 +42,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
|
||||
fetchTaxTypes(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/tax-types`, { params })
|
||||
.then((response) => {
|
||||
this.taxTypes = response.data.data
|
||||
@@ -59,7 +57,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
|
||||
fetchTaxType(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.get(`/api/v1/tax-types/${id}`)
|
||||
.then((response) => {
|
||||
this.currentTaxType = response.data.data
|
||||
@@ -75,7 +73,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
addTaxType(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/v1/tax-types', data)
|
||||
.then((response) => {
|
||||
this.taxTypes.push(response.data.data)
|
||||
@@ -95,7 +93,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
updateTaxType(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.put(`/api/v1/tax-types/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -119,7 +117,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
|
||||
fetchSalesTax(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.post('/api/m/sales-tax-us/current-tax', data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@@ -141,7 +139,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
|
||||
deleteTaxType(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
http
|
||||
.delete(`/api/v1/tax-types/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data.success) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user