mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
v6 update
This commit is contained in:
5
resources/sass/crater.scss
vendored
5
resources/sass/crater.scss
vendored
@ -44,6 +44,11 @@
|
||||
src: url("/fonts/Poppins-Semibold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
// Default Theme
|
||||
//----------------------------------
|
||||
|
||||
@import "themes.scss";
|
||||
|
||||
// Base Components
|
||||
//----------------------------------
|
||||
|
||||
|
||||
12
resources/sass/themes.scss
vendored
Normal file
12
resources/sass/themes.scss
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
:root {
|
||||
--color-primary-50: 247, 246, 253;
|
||||
--color-primary-100: 238, 238, 251;
|
||||
--color-primary-200: 213, 212, 245;
|
||||
--color-primary-300: 188, 185, 239;
|
||||
--color-primary-400: 138, 133, 228;
|
||||
--color-primary-500: 88, 81, 216;
|
||||
--color-primary-600: 79, 73, 194;
|
||||
--color-primary-700: 53, 49, 130;
|
||||
--color-primary-800: 40, 36, 97;
|
||||
--color-primary-900: 26, 24, 65;
|
||||
}
|
||||
@ -2,14 +2,13 @@ import { createApp } from 'vue'
|
||||
import App from '@/scripts/App.vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import messages from '@/scripts/locales/locales'
|
||||
import router from '@/scripts/router'
|
||||
import router from '@/scripts/router/index'
|
||||
import { defineGlobalComponents } from './global-components'
|
||||
import utils from '@/scripts/helpers/utilities.js'
|
||||
import _ from 'lodash'
|
||||
import Maska from 'maska'
|
||||
import { VTooltip } from 'v-tooltip'
|
||||
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
export default class Crater {
|
||||
|
||||
493
resources/scripts/admin/admin-router.js
Normal file
493
resources/scripts/admin/admin-router.js
Normal file
@ -0,0 +1,493 @@
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const LayoutInstallation = () =>
|
||||
import('@/scripts/admin/layouts/LayoutInstallation.vue')
|
||||
|
||||
const Login = () => import('@/scripts/admin/views/auth/Login.vue')
|
||||
const LayoutBasic = () => import('@/scripts/admin/layouts/LayoutBasic.vue')
|
||||
const LayoutLogin = () => import('@/scripts/admin/layouts/LayoutLogin.vue')
|
||||
const ResetPassword = () =>
|
||||
import('@/scripts/admin/views/auth/ResetPassword.vue')
|
||||
const ForgotPassword = () =>
|
||||
import('@/scripts/admin/views/auth/ForgotPassword.vue')
|
||||
|
||||
// Dashboard
|
||||
const Dashboard = () => import('@/scripts/admin/views/dashboard/Dashboard.vue')
|
||||
|
||||
// Customers
|
||||
const CustomerIndex = () => import('@/scripts/admin/views/customers/Index.vue')
|
||||
const CustomerCreate = () =>
|
||||
import('@/scripts/admin/views/customers/Create.vue')
|
||||
const CustomerView = () => import('@/scripts/admin/views/customers/View.vue')
|
||||
|
||||
//Settings
|
||||
const SettingsIndex = () =>
|
||||
import('@/scripts/admin/views/settings/SettingsIndex.vue')
|
||||
const AccountSetting = () =>
|
||||
import('@/scripts/admin/views/settings/AccountSetting.vue')
|
||||
const CompanyInfo = () =>
|
||||
import('@/scripts/admin/views/settings/CompanyInfoSettings.vue')
|
||||
const Preferences = () =>
|
||||
import('@/scripts/admin/views/settings/PreferencesSetting.vue')
|
||||
const Customization = () =>
|
||||
import(
|
||||
'@/scripts/admin/views/settings/customization/CustomizationSetting.vue'
|
||||
)
|
||||
const Notifications = () =>
|
||||
import('@/scripts/admin/views/settings/NotificationsSetting.vue')
|
||||
const TaxTypes = () =>
|
||||
import('@/scripts/admin/views/settings/TaxTypesSetting.vue')
|
||||
const PaymentMode = () =>
|
||||
import('@/scripts/admin/views/settings/PaymentsModeSetting.vue')
|
||||
const CustomFieldsIndex = () =>
|
||||
import('@/scripts/admin/views/settings/CustomFieldsSetting.vue')
|
||||
const NotesSetting = () =>
|
||||
import('@/scripts/admin/views/settings/NotesSetting.vue')
|
||||
const ExpenseCategory = () =>
|
||||
import('@/scripts/admin/views/settings/ExpenseCategorySetting.vue')
|
||||
const ExchangeRateSetting = () =>
|
||||
import('@/scripts/admin/views/settings/ExchangeRateProviderSetting.vue')
|
||||
const MailConfig = () =>
|
||||
import('@/scripts/admin/views/settings/MailConfigSetting.vue')
|
||||
const FileDisk = () =>
|
||||
import('@/scripts/admin/views/settings/FileDiskSetting.vue')
|
||||
const Backup = () => import('@/scripts/admin/views/settings/BackupSetting.vue')
|
||||
const UpdateApp = () =>
|
||||
import('@/scripts/admin/views/settings/UpdateAppSetting.vue')
|
||||
const RolesSettings = () =>
|
||||
import('@/scripts/admin/views/settings/RolesSettings.vue')
|
||||
|
||||
// Items
|
||||
const ItemsIndex = () => import('@/scripts/admin/views/items/Index.vue')
|
||||
const ItemCreate = () => import('@/scripts/admin/views/items/Create.vue')
|
||||
|
||||
// Expenses
|
||||
const ExpensesIndex = () => import('@/scripts/admin/views/expenses/Index.vue')
|
||||
const ExpenseCreate = () => import('@/scripts/admin/views/expenses/Create.vue')
|
||||
|
||||
// Users
|
||||
const UserIndex = () => import('@/scripts/admin/views/users/Index.vue')
|
||||
const UserCreate = () => import('@/scripts/admin/views/users/Create.vue')
|
||||
|
||||
// Estimates
|
||||
const EstimateIndex = () => import('@/scripts/admin/views/estimates/Index.vue')
|
||||
const EstimateCreate = () =>
|
||||
import('@/scripts/admin/views/estimates/create/EstimateCreate.vue')
|
||||
const EstimateView = () => import('@/scripts/admin/views/estimates/View.vue')
|
||||
|
||||
// Payments
|
||||
const PaymentsIndex = () => import('@/scripts/admin/views/payments/Index.vue')
|
||||
const PaymentCreate = () => import('@/scripts/admin/views/payments/Create.vue')
|
||||
const PaymentView = () => import('@/scripts/admin/views/payments/View.vue')
|
||||
|
||||
const NotFoundPage = () => import('@/scripts/admin/views/errors/404.vue')
|
||||
|
||||
// Invoice
|
||||
const InvoiceIndex = () => import('@/scripts/admin/views/invoices/Index.vue')
|
||||
const InvoiceCreate = () =>
|
||||
import('@/scripts/admin/views/invoices/create/InvoiceCreate.vue')
|
||||
const InvoiceView = () => import('@/scripts/admin/views/invoices/View.vue')
|
||||
|
||||
// Recurring Invoice
|
||||
const RecurringInvoiceIndex = () =>
|
||||
import('@/scripts/admin/views/recurring-invoices/Index.vue')
|
||||
const RecurringInvoiceCreate = () =>
|
||||
import(
|
||||
'@/scripts/admin/views/recurring-invoices/create/RecurringInvoiceCreate.vue'
|
||||
)
|
||||
const RecurringInvoiceView = () =>
|
||||
import('@/scripts/admin/views/recurring-invoices/View.vue')
|
||||
|
||||
// Reports
|
||||
const ReportsIndex = () =>
|
||||
import('@/scripts/admin/views/reports/layout/Index.vue')
|
||||
|
||||
// Installation
|
||||
const Installation = () =>
|
||||
import('@/scripts/admin/views/installation/Installation.vue')
|
||||
|
||||
// Modules
|
||||
const ModuleIndex = () => import('@/scripts/admin/views/modules/Index.vue')
|
||||
|
||||
const ModuleView = () => import('@/scripts/admin/views/modules/View.vue')
|
||||
const InvoicePublicPage = () =>
|
||||
import('@/scripts/components/InvoicePublicPage.vue')
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/installation',
|
||||
component: LayoutInstallation,
|
||||
meta: { requiresAuth: false },
|
||||
children: [
|
||||
{
|
||||
path: '/installation',
|
||||
component: Installation,
|
||||
name: 'installation',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
path: '/customer/invoices/view/:hash',
|
||||
component: InvoicePublicPage,
|
||||
name: 'invoice.public',
|
||||
},
|
||||
|
||||
{
|
||||
path: '/',
|
||||
component: LayoutLogin,
|
||||
meta: { requiresAuth: false, redirectIfAuthenticated: true },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: Login,
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
name: 'login',
|
||||
component: Login,
|
||||
},
|
||||
{
|
||||
path: 'forgot-password',
|
||||
component: ForgotPassword,
|
||||
name: 'forgot-password',
|
||||
},
|
||||
{
|
||||
path: '/reset-password/:token',
|
||||
component: ResetPassword,
|
||||
name: 'reset-password',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/admin',
|
||||
component: LayoutBasic,
|
||||
meta: { requiresAuth: true },
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
name: 'dashboard',
|
||||
meta: { ability: abilities.DASHBOARD },
|
||||
component: Dashboard,
|
||||
},
|
||||
|
||||
// Customers
|
||||
{
|
||||
path: 'customers',
|
||||
meta: { ability: abilities.VIEW_CUSTOMER },
|
||||
component: CustomerIndex,
|
||||
},
|
||||
{
|
||||
path: 'customers/create',
|
||||
name: 'customers.create',
|
||||
meta: { ability: abilities.CREATE_CUSTOMER },
|
||||
component: CustomerCreate,
|
||||
},
|
||||
{
|
||||
path: 'customers/:id/edit',
|
||||
name: 'customers.edit',
|
||||
meta: { ability: abilities.EDIT_CUSTOMER },
|
||||
component: CustomerCreate,
|
||||
},
|
||||
{
|
||||
path: 'customers/:id/view',
|
||||
name: 'customers.view',
|
||||
meta: { ability: abilities.VIEW_CUSTOMER },
|
||||
component: CustomerView,
|
||||
},
|
||||
// Payments
|
||||
{
|
||||
path: 'payments',
|
||||
meta: { ability: abilities.VIEW_PAYMENT },
|
||||
component: PaymentsIndex,
|
||||
},
|
||||
{
|
||||
path: 'payments/create',
|
||||
name: 'payments.create',
|
||||
meta: { ability: abilities.CREATE_PAYMENT },
|
||||
component: PaymentCreate,
|
||||
},
|
||||
{
|
||||
path: 'payments/:id/create',
|
||||
name: 'invoice.payments.create',
|
||||
meta: { ability: abilities.CREATE_PAYMENT },
|
||||
component: PaymentCreate,
|
||||
},
|
||||
{
|
||||
path: 'payments/:id/edit',
|
||||
name: 'payments.edit',
|
||||
meta: { ability: abilities.EDIT_PAYMENT },
|
||||
component: PaymentCreate,
|
||||
},
|
||||
{
|
||||
path: 'payments/:id/view',
|
||||
name: 'payments.view',
|
||||
meta: { ability: abilities.VIEW_PAYMENT },
|
||||
component: PaymentView,
|
||||
},
|
||||
|
||||
//settings
|
||||
{
|
||||
path: 'settings',
|
||||
name: 'settings',
|
||||
component: SettingsIndex,
|
||||
children: [
|
||||
{
|
||||
path: 'account-settings',
|
||||
name: 'account.settings',
|
||||
component: AccountSetting,
|
||||
},
|
||||
{
|
||||
path: 'company-info',
|
||||
name: 'company.info',
|
||||
meta: { isOwner: true },
|
||||
component: CompanyInfo,
|
||||
},
|
||||
{
|
||||
path: 'preferences',
|
||||
name: 'preferences',
|
||||
meta: { isOwner: true },
|
||||
component: Preferences,
|
||||
},
|
||||
{
|
||||
path: 'customization',
|
||||
name: 'customization',
|
||||
meta: { isOwner: true },
|
||||
component: Customization,
|
||||
},
|
||||
{
|
||||
path: 'notifications',
|
||||
name: 'notifications',
|
||||
meta: { isOwner: true },
|
||||
component: Notifications,
|
||||
},
|
||||
{
|
||||
path: 'roles-settings',
|
||||
name: 'roles.settings',
|
||||
meta: { isOwner: true },
|
||||
component: RolesSettings,
|
||||
},
|
||||
{
|
||||
path: 'exchange-rate-provider',
|
||||
name: 'exchange.rate.provider',
|
||||
meta: { ability: abilities.VIEW_EXCHANGE_RATE },
|
||||
component: ExchangeRateSetting,
|
||||
},
|
||||
{
|
||||
path: 'tax-types',
|
||||
name: 'tax.types',
|
||||
meta: { ability: abilities.VIEW_TAX_TYPE },
|
||||
component: TaxTypes,
|
||||
},
|
||||
{
|
||||
path: 'notes',
|
||||
name: 'notes',
|
||||
meta: { ability: abilities.VIEW_ALL_NOTES },
|
||||
component: NotesSetting,
|
||||
},
|
||||
{
|
||||
path: 'payment-mode',
|
||||
name: 'payment.mode',
|
||||
component: PaymentMode,
|
||||
},
|
||||
{
|
||||
path: 'custom-fields',
|
||||
name: 'custom.fields',
|
||||
meta: { ability: abilities.VIEW_CUSTOM_FIELDS },
|
||||
component: CustomFieldsIndex,
|
||||
},
|
||||
{
|
||||
path: 'expense-category',
|
||||
name: 'expense.category',
|
||||
meta: { ability: abilities.VIEW_EXPENSE },
|
||||
component: ExpenseCategory,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'mail-configuration',
|
||||
name: 'mailconfig',
|
||||
meta: { isOwner: true },
|
||||
component: MailConfig,
|
||||
},
|
||||
{
|
||||
path: 'file-disk',
|
||||
name: 'file-disk',
|
||||
meta: { isOwner: true },
|
||||
component: FileDisk,
|
||||
},
|
||||
{
|
||||
path: 'backup',
|
||||
name: 'backup',
|
||||
meta: { isOwner: true },
|
||||
component: Backup,
|
||||
},
|
||||
{
|
||||
path: 'update-app',
|
||||
name: 'updateapp',
|
||||
meta: { isOwner: true },
|
||||
component: UpdateApp,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Items
|
||||
{
|
||||
path: 'items',
|
||||
meta: { ability: abilities.VIEW_ITEM },
|
||||
component: ItemsIndex,
|
||||
},
|
||||
{
|
||||
path: 'items/create',
|
||||
name: 'items.create',
|
||||
meta: { ability: abilities.CREATE_ITEM },
|
||||
component: ItemCreate,
|
||||
},
|
||||
{
|
||||
path: 'items/:id/edit',
|
||||
name: 'items.edit',
|
||||
meta: { ability: abilities.EDIT_ITEM },
|
||||
component: ItemCreate,
|
||||
},
|
||||
|
||||
// Expenses
|
||||
{
|
||||
path: 'expenses',
|
||||
meta: { ability: abilities.VIEW_EXPENSE },
|
||||
component: ExpensesIndex,
|
||||
},
|
||||
{
|
||||
path: 'expenses/create',
|
||||
name: 'expenses.create',
|
||||
meta: { ability: abilities.CREATE_EXPENSE },
|
||||
component: ExpenseCreate,
|
||||
},
|
||||
{
|
||||
path: 'expenses/:id/edit',
|
||||
name: 'expenses.edit',
|
||||
meta: { ability: abilities.EDIT_EXPENSE },
|
||||
component: ExpenseCreate,
|
||||
},
|
||||
|
||||
// Users
|
||||
{
|
||||
path: 'users',
|
||||
name: 'users.index',
|
||||
meta: { isOwner: true },
|
||||
component: UserIndex,
|
||||
},
|
||||
{
|
||||
path: 'users/create',
|
||||
meta: { isOwner: true },
|
||||
name: 'users.create',
|
||||
component: UserCreate,
|
||||
},
|
||||
{
|
||||
path: 'users/:id/edit',
|
||||
name: 'users.edit',
|
||||
meta: { isOwner: true },
|
||||
component: UserCreate,
|
||||
},
|
||||
|
||||
// Estimates
|
||||
{
|
||||
path: 'estimates',
|
||||
name: 'estimates.index',
|
||||
meta: { ability: abilities.VIEW_ESTIMATE },
|
||||
component: EstimateIndex,
|
||||
},
|
||||
{
|
||||
path: 'estimates/create',
|
||||
name: 'estimates.create',
|
||||
meta: { ability: abilities.CREATE_ESTIMATE },
|
||||
component: EstimateCreate,
|
||||
},
|
||||
{
|
||||
path: 'estimates/:id/view',
|
||||
name: 'estimates.view',
|
||||
meta: { ability: abilities.VIEW_ESTIMATE },
|
||||
component: EstimateView,
|
||||
},
|
||||
{
|
||||
path: 'estimates/:id/edit',
|
||||
name: 'estimates.edit',
|
||||
meta: { ability: abilities.EDIT_ESTIMATE },
|
||||
component: EstimateCreate,
|
||||
},
|
||||
|
||||
// Invoices
|
||||
{
|
||||
path: 'invoices',
|
||||
name: 'invoices.index',
|
||||
meta: { ability: abilities.VIEW_INVOICE },
|
||||
component: InvoiceIndex,
|
||||
},
|
||||
{
|
||||
path: 'invoices/create',
|
||||
name: 'invoices.create',
|
||||
meta: { ability: abilities.CREATE_INVOICE },
|
||||
component: InvoiceCreate,
|
||||
},
|
||||
{
|
||||
path: 'invoices/:id/view',
|
||||
name: 'invoices.view',
|
||||
meta: { ability: abilities.VIEW_INVOICE },
|
||||
component: InvoiceView,
|
||||
},
|
||||
{
|
||||
path: 'invoices/:id/edit',
|
||||
name: 'invoices.edit',
|
||||
meta: { ability: abilities.EDIT_INVOICE },
|
||||
component: InvoiceCreate,
|
||||
},
|
||||
|
||||
// Recurring Invoices
|
||||
{
|
||||
path: 'recurring-invoices',
|
||||
name: 'recurring-invoices.index',
|
||||
meta: { ability: abilities.VIEW_RECURRING_INVOICE },
|
||||
component: RecurringInvoiceIndex,
|
||||
},
|
||||
{
|
||||
path: 'recurring-invoices/create',
|
||||
name: 'recurring-invoices.create',
|
||||
meta: { ability: abilities.CREATE_RECURRING_INVOICE },
|
||||
component: RecurringInvoiceCreate,
|
||||
},
|
||||
{
|
||||
path: 'recurring-invoices/:id/view',
|
||||
name: 'recurring-invoices.view',
|
||||
meta: { ability: abilities.VIEW_RECURRING_INVOICE },
|
||||
component: RecurringInvoiceView,
|
||||
},
|
||||
{
|
||||
path: 'recurring-invoices/:id/edit',
|
||||
name: 'recurring-invoices.edit',
|
||||
meta: { ability: abilities.EDIT_RECURRING_INVOICE },
|
||||
component: RecurringInvoiceCreate,
|
||||
},
|
||||
|
||||
// Modules
|
||||
{
|
||||
path: 'modules',
|
||||
name: 'modules.index',
|
||||
meta: { isOwner: true },
|
||||
component: ModuleIndex,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'modules/:slug',
|
||||
name: 'modules.view',
|
||||
meta: { isOwner: true },
|
||||
component: ModuleView,
|
||||
},
|
||||
|
||||
// Reports
|
||||
{
|
||||
path: 'reports',
|
||||
meta: { ability: abilities.VIEW_FINANCIAL_REPORT },
|
||||
component: ReportsIndex,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ path: '/:catchAll(.*)', component: NotFoundPage },
|
||||
]
|
||||
98
resources/scripts/admin/components/CopyInputField.vue
Normal file
98
resources/scripts/admin/components/CopyInputField.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div
|
||||
class="
|
||||
relative
|
||||
flex
|
||||
px-4
|
||||
py-2
|
||||
rounded-lg
|
||||
bg-opacity-40 bg-gray-300
|
||||
whitespace-nowrap
|
||||
flex-col
|
||||
mt-1
|
||||
"
|
||||
>
|
||||
<span
|
||||
ref="publicUrl"
|
||||
class="
|
||||
pr-10
|
||||
text-sm
|
||||
font-medium
|
||||
text-black
|
||||
truncate
|
||||
select-all select-color
|
||||
"
|
||||
>
|
||||
{{ token }}
|
||||
</span>
|
||||
<svg
|
||||
v-tooltip="{ content: 'Copy to Clipboard' }"
|
||||
class="
|
||||
absolute
|
||||
right-0
|
||||
h-full
|
||||
inset-y-0
|
||||
cursor-pointer
|
||||
focus:outline-none
|
||||
text-primary-500
|
||||
"
|
||||
width="37"
|
||||
viewBox="0 0 37 37"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@click="copyUrl"
|
||||
>
|
||||
<rect width="37" height="37" rx="10" fill="currentColor" />
|
||||
<path
|
||||
d="M16 10C15.7348 10 15.4804 10.1054 15.2929 10.2929C15.1054 10.4804 15 10.7348 15 11C15 11.2652 15.1054 11.5196 15.2929 11.7071C15.4804 11.8946 15.7348 12 16 12H18C18.2652 12 18.5196 11.8946 18.7071 11.7071C18.8946 11.5196 19 11.2652 19 11C19 10.7348 18.8946 10.4804 18.7071 10.2929C18.5196 10.1054 18.2652 10 18 10H16Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11 13C11 12.4696 11.2107 11.9609 11.5858 11.5858C11.9609 11.2107 12.4696 11 13 11C13 11.7956 13.3161 12.5587 13.8787 13.1213C14.4413 13.6839 15.2044 14 16 14H18C18.7956 14 19.5587 13.6839 20.1213 13.1213C20.6839 12.5587 21 11.7956 21 11C21.5304 11 22.0391 11.2107 22.4142 11.5858C22.7893 11.9609 23 12.4696 23 13V19H18.414L19.707 17.707C19.8892 17.5184 19.99 17.2658 19.9877 17.0036C19.9854 16.7414 19.8802 16.4906 19.6948 16.3052C19.5094 16.1198 19.2586 16.0146 18.9964 16.0123C18.7342 16.01 18.4816 16.1108 18.293 16.293L15.293 19.293C15.1055 19.4805 15.0002 19.7348 15.0002 20C15.0002 20.2652 15.1055 20.5195 15.293 20.707L18.293 23.707C18.4816 23.8892 18.7342 23.99 18.9964 23.9877C19.2586 23.9854 19.5094 23.8802 19.6948 23.6948C19.8802 23.5094 19.9854 23.2586 19.9877 22.9964C19.99 22.7342 19.8892 22.4816 19.707 22.293L18.414 21H23V24C23 24.5304 22.7893 25.0391 22.4142 25.4142C22.0391 25.7893 21.5304 26 21 26H13C12.4696 26 11.9609 25.7893 11.5858 25.4142C11.2107 25.0391 11 24.5304 11 24V13ZM23 19H25C25.2652 19 25.5196 19.1054 25.7071 19.2929C25.8946 19.4804 26 19.7348 26 20C26 20.2652 25.8946 20.5196 25.7071 20.7071C25.5196 20.8946 25.2652 21 25 21H23V19Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { ref } from 'vue'
|
||||
const notificationStore = useNotificationStore()
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const publicUrl = ref('')
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
token: {
|
||||
type: String,
|
||||
default: null,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
function selectText(element) {
|
||||
let range
|
||||
if (document.selection) {
|
||||
// IE
|
||||
range = document.body.createTextRange()
|
||||
range.moveToElementText(element)
|
||||
range.select()
|
||||
} else if (window.getSelection) {
|
||||
range = document.createRange()
|
||||
range.selectNode(element)
|
||||
window.getSelection().removeAllRanges()
|
||||
window.getSelection().addRange(range)
|
||||
}
|
||||
}
|
||||
|
||||
function copyUrl() {
|
||||
selectText(publicUrl.value)
|
||||
document.execCommand('copy')
|
||||
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: t('general.copied_url_clipboard'),
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@ -38,7 +38,6 @@
|
||||
z-20
|
||||
px-4
|
||||
mt-3
|
||||
transform
|
||||
sm:px-0
|
||||
w-screen
|
||||
max-w-full
|
||||
@ -148,11 +147,11 @@
|
||||
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
|
||||
import { computed, ref, inject } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useNotesStore } from '@/scripts/stores/note'
|
||||
import { useNotesStore } from '@/scripts/admin/stores/note'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import NoteModal from '@/scripts/components/modal-components/NoteModal.vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import NoteModal from '@/scripts/admin/components/modal-components/NoteModal.vue'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
@ -7,7 +7,7 @@
|
||||
<script setup>
|
||||
import Chart from 'chart.js'
|
||||
import { ref, reactive, computed, onMounted, watchEffect, inject } from 'vue'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
|
||||
const utils = inject('utils')
|
||||
|
||||
@ -70,8 +70,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useExchangeRateStore } from '@/scripts/stores/exchange-rate'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useExchangeRateStore } from '@/scripts/admin/stores/exchange-rate'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { computed, ref } from '@vue/runtime-core'
|
||||
@ -21,7 +21,7 @@
|
||||
<script setup>
|
||||
import moment from 'moment'
|
||||
import lodash from 'lodash'
|
||||
import { useCustomFieldStore } from '@/scripts/stores/custom-field'
|
||||
import { useCustomFieldStore } from '@/scripts/admin/stores/custom-field'
|
||||
import { watch } from 'vue'
|
||||
import SingleField from './CreateCustomFieldsSingle.vue'
|
||||
|
||||
@ -34,12 +34,12 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useCustomFieldStore } from '@/scripts/stores/custom-field'
|
||||
import { useCustomFieldStore } from '@/scripts/admin/stores/custom-field'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -53,15 +53,15 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useCustomerStore } from '@/scripts/stores/customer'
|
||||
import { useCustomerStore } from '@/scripts/admin/stores/customer'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { inject } from 'vue'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -148,15 +148,15 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -40,12 +40,12 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useCategoryStore } from '@/scripts/stores/category'
|
||||
import { useCategoryStore } from '@/scripts/admin/stores/category'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -39,11 +39,11 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useExpenseStore } from '@/scripts/stores/expense'
|
||||
import { useExpenseStore } from '@/scripts/admin/stores/expense'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -114,15 +114,15 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { inject } from 'vue'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -153,7 +153,6 @@ const utils = inject('utils')
|
||||
function canReSendInvoice(row) {
|
||||
return (
|
||||
(row.status == 'SENT' || row.status == 'VIEWED') &&
|
||||
route.name !== 'invoices.view' &&
|
||||
userStore.hasAbilities(abilities.SEND_INVOICE)
|
||||
)
|
||||
}
|
||||
@ -39,11 +39,11 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useItemStore } from '@/scripts/stores/item'
|
||||
import { useItemStore } from '@/scripts/admin/stores/item'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -37,12 +37,12 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useNotesStore } from '@/scripts/stores/note'
|
||||
import { useNotesStore } from '@/scripts/admin/stores/note'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -89,11 +89,11 @@ import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { usePaymentStore } from '@/scripts/stores/payment'
|
||||
import { usePaymentStore } from '@/scripts/admin/stores/payment'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -31,10 +31,10 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { usePaymentStore } from '@/scripts/stores/payment'
|
||||
import { usePaymentStore } from '@/scripts/admin/stores/payment'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
|
||||
const props = defineProps({
|
||||
@ -56,16 +56,16 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { inject } from 'vue'
|
||||
import { useRecurringInvoiceStore } from '@/scripts/stores/recurring-invoice'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import { useRecurringInvoiceStore } from '@/scripts/admin/stores/recurring-invoice'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -37,10 +37,10 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoleStore } from '@/scripts/stores/role'
|
||||
import { useRoleStore } from '@/scripts/admin/stores/role'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
|
||||
const props = defineProps({
|
||||
@ -37,12 +37,12 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useTaxTypeStore } from '@/scripts/stores/tax-type'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -33,10 +33,10 @@
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useUsersStore } from '@/scripts/stores/users'
|
||||
import { useUsersStore } from '@/scripts/admin/stores/users'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
@ -190,10 +190,10 @@ import { computed, ref, inject } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Guid from 'guid'
|
||||
import TaxStub from '@/scripts/stub/tax'
|
||||
import TaxStub from '@/scripts/admin/stub/tax'
|
||||
import ItemTax from './CreateItemRowTax.vue'
|
||||
import { sumBy } from 'lodash'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
import {
|
||||
required,
|
||||
between,
|
||||
@ -202,8 +202,8 @@ import {
|
||||
minValue,
|
||||
} from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useItemStore } from '@/scripts/stores/item'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useItemStore } from '@/scripts/admin/stores/item'
|
||||
import DragIcon from '@/scripts/components/icons/DragIcon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
@ -73,10 +73,10 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, inject, reactive, watch } from 'vue'
|
||||
import { useTaxTypeStore } from '@/scripts/stores/tax-type'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
|
||||
const props = defineProps({
|
||||
ability: {
|
||||
@ -154,7 +154,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { computed } from 'vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import Item from './CreateItemRow.vue'
|
||||
@ -5,7 +5,7 @@
|
||||
>
|
||||
<SelectNotePopup :type="type" @select="onSelectNote" />
|
||||
</div>
|
||||
<label class="text-primary-800 font-medium mb-4 text-sm">
|
||||
<label class="text-gray-800 font-medium mb-4 text-sm">
|
||||
{{ $t('invoices.notes') }}
|
||||
</label>
|
||||
<BaseCustomInput
|
||||
@ -223,9 +223,9 @@
|
||||
import { computed, inject, ref } from 'vue'
|
||||
import Guid from 'guid'
|
||||
import Tax from './CreateTotalTaxes.vue'
|
||||
import TaxStub from '@/scripts/stub/tax'
|
||||
import TaxStub from '@/scripts/admin/stub/abilities'
|
||||
import SelectTaxPopup from './SelectTaxPopup.vue'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
|
||||
const taxModal = ref(null)
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
name="RefreshIcon"
|
||||
:class="`h-4 w-4 text-primary-500 cursor-pointer outline-none ${
|
||||
isFetching
|
||||
? ' animate-spin transform rotate-180 cursor-not-allowed pointer-events-none '
|
||||
? ' animate-spin rotate-180 cursor-not-allowed pointer-events-none '
|
||||
: ''
|
||||
}`"
|
||||
@click="getCurrenctExchangeRate(customerCurrency)"
|
||||
@ -46,9 +46,9 @@
|
||||
|
||||
<script setup>
|
||||
import { watch, computed, ref, onBeforeUnmount } from 'vue'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useExchangeRateStore } from '@/scripts/stores/exchange-rate'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useExchangeRateStore } from '@/scripts/admin/stores/exchange-rate'
|
||||
|
||||
const props = defineProps({
|
||||
v: {
|
||||
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<TaxationAddressModal @addTax="addSalesTax" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {} from '@/scripts/admin/stores/recurring-invoice'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, watch, onMounted, ref, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import TaxationAddressModal from '@/scripts/admin/components/modal-components/TaxationAddressModal.vue'
|
||||
const SALES_TAX_US = 'Sales Tax'
|
||||
const SALES_TAX_MODULE = 'MODULE'
|
||||
const modalStore = useModalStore()
|
||||
const companyStore = useCompanyStore()
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
const { t } = useI18n()
|
||||
import { isEqual, pick } from 'lodash'
|
||||
|
||||
const fetchingTax = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
customer: {
|
||||
type: [Object],
|
||||
default: null,
|
||||
},
|
||||
store: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
storeProp: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
|
||||
const isSalesTaxTypeBilling = computed(() => {
|
||||
return props.isEdit
|
||||
? props.store[props.storeProp].sales_tax_address_type === 'billing'
|
||||
: companyStore.selectedCompanySettings.sales_tax_address_type === 'billing'
|
||||
})
|
||||
|
||||
const salesTaxEnabled = computed(() => {
|
||||
return companyStore.selectedCompanySettings.sales_tax_us_enabled === 'YES'
|
||||
})
|
||||
|
||||
const salesTaxCustomerLevel = computed(() => {
|
||||
return props.isEdit
|
||||
? props.store[props.storeProp].sales_tax_type === 'customer_level'
|
||||
: companyStore.selectedCompanySettings.sales_tax_type === 'customer_level'
|
||||
})
|
||||
|
||||
const salesTaxCompanyLevel = computed(() => {
|
||||
return props.isEdit
|
||||
? props.store[props.storeProp].sales_tax_type === 'company_level'
|
||||
: companyStore.selectedCompanySettings.sales_tax_type === 'company_level'
|
||||
})
|
||||
|
||||
const addressData = computed(() => {
|
||||
if (salesTaxCustomerLevel.value && isAddressAvailable.value) {
|
||||
let address = isSalesTaxTypeBilling.value
|
||||
? props.customer.billing
|
||||
: props.customer.shipping
|
||||
return {
|
||||
address: pick(address, ['address_street_1', 'city', 'state', 'zip']),
|
||||
customer_id: props.customer.id,
|
||||
}
|
||||
} else if (salesTaxCompanyLevel.value && isAddressAvailable.value) {
|
||||
return {
|
||||
address: pick(address, ['address_street_1', 'city', 'state', 'zip']),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const isAddressAvailable = computed(() => {
|
||||
if (salesTaxCustomerLevel.value) {
|
||||
let address = isSalesTaxTypeBilling.value
|
||||
? props.customer?.billing
|
||||
: props.customer?.shipping
|
||||
|
||||
return hasAddress(address)
|
||||
} else if (salesTaxCompanyLevel.value) {
|
||||
return hasAddress(companyStore.selectedCompany.address)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.customer,
|
||||
(v, o) => {
|
||||
if (v && o && salesTaxCustomerLevel.value) {
|
||||
// call if customer changed address
|
||||
isCustomerAddressChanged(v, o)
|
||||
return
|
||||
}
|
||||
if (!isAddressAvailable.value && salesTaxCustomerLevel.value && v) {
|
||||
setTimeout(() => {
|
||||
openAddressModal()
|
||||
}, 500)
|
||||
} else if (salesTaxCustomerLevel.value && v) {
|
||||
fetchSalesTax()
|
||||
} else if (salesTaxCustomerLevel.value && !v) {
|
||||
removeSalesTax()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Open modal for company address
|
||||
onMounted(() => {
|
||||
if (salesTaxCompanyLevel.value) {
|
||||
isAddressAvailable.value ? fetchSalesTax() : openAddressModal()
|
||||
}
|
||||
})
|
||||
|
||||
function hasAddress(address) {
|
||||
if (!address) return false
|
||||
|
||||
return (
|
||||
address.address_street_1 && address.city && address.state && address.zip
|
||||
)
|
||||
}
|
||||
|
||||
function isCustomerAddressChanged(newV, oldV) {
|
||||
const newData = isSalesTaxTypeBilling.value ? newV.billing : newV.shipping
|
||||
const oldData = isSalesTaxTypeBilling.value ? oldV.billing : oldV.shipping
|
||||
|
||||
const newAdd = pick(newData, ['address_street_1', 'city', 'state', 'zip'])
|
||||
const oldAdd = pick(oldData, ['address_street_1', 'city', 'state', 'zip'])
|
||||
!isEqual(newAdd, oldAdd) ? fetchSalesTax() : ''
|
||||
}
|
||||
|
||||
function openAddressModal() {
|
||||
if (!salesTaxEnabled.value) return
|
||||
let modalData = null
|
||||
let title = ''
|
||||
if (salesTaxCustomerLevel.value) {
|
||||
if (isSalesTaxTypeBilling.value) {
|
||||
modalData = props.customer?.billing
|
||||
title = t('settings.taxations.add_billing_address')
|
||||
} else {
|
||||
modalData = props.customer?.shipping
|
||||
title = t('settings.taxations.add_shipping_address')
|
||||
}
|
||||
} else {
|
||||
modalData = companyStore.selectedCompany.address
|
||||
title = t('settings.taxations.add_company_address')
|
||||
}
|
||||
|
||||
modalStore.openModal({
|
||||
title: title,
|
||||
content: t('settings.taxations.modal_description'),
|
||||
componentName: 'TaxationAddressModal',
|
||||
data: modalData,
|
||||
id: salesTaxCustomerLevel.value ? props.customer.id : '',
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchSalesTax() {
|
||||
if (!salesTaxEnabled.value) return
|
||||
|
||||
fetchingTax.value = true
|
||||
await taxTypeStore
|
||||
.fetchSalesTax(addressData.value)
|
||||
.then((res) => {
|
||||
addSalesTax(res.data.data)
|
||||
fetchingTax.value = false
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.data.error) {
|
||||
setTimeout(() => {
|
||||
openAddressModal()
|
||||
}, 500)
|
||||
}
|
||||
fetchingTax.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function addSalesTax(tax) {
|
||||
tax.tax_type_id = tax.id
|
||||
|
||||
const i = props.store[props.storeProp].taxes.findIndex(
|
||||
(_t) => _t.name === SALES_TAX_US && _t.type === SALES_TAX_MODULE
|
||||
)
|
||||
|
||||
if (i > -1) {
|
||||
Object.assign(props.store[props.storeProp].taxes[i], tax)
|
||||
} else {
|
||||
props.store[props.storeProp].taxes.push(tax)
|
||||
}
|
||||
}
|
||||
|
||||
function removeSalesTax() {
|
||||
// remove from total taxes
|
||||
const i = props.store[props.storeProp].taxes.findIndex(
|
||||
(_t) => _t.name === SALES_TAX_US && _t.type === SALES_TAX_MODULE
|
||||
)
|
||||
i > -1 ? props.store[props.storeProp].taxes.splice(i, 1) : ''
|
||||
|
||||
// remove from tax-type list
|
||||
let pos = taxTypeStore.taxTypes.findIndex(
|
||||
(_t) => _t.name === SALES_TAX_US && _t.type === SALES_TAX_MODULE
|
||||
)
|
||||
|
||||
pos > -1 ? taxTypeStore.taxTypes.splice(pos, 1) : ''
|
||||
}
|
||||
</script>
|
||||
@ -32,7 +32,7 @@
|
||||
<PopoverPanel
|
||||
v-slot="{ close }"
|
||||
style="min-width: 350px; margin-left: 62px; top: -28px"
|
||||
class="absolute z-10 px-4 py-2 transform -translate-x-full sm:px-0"
|
||||
class="absolute z-10 px-4 py-2 -translate-x-full sm:px-0"
|
||||
>
|
||||
<div
|
||||
class="
|
||||
@ -168,12 +168,12 @@
|
||||
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
|
||||
import { computed, ref, inject, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useTaxTypeStore } from '@/scripts/stores/tax-type'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<label class="flex text-primary-800 font-medium text-sm mb-2">
|
||||
<label class="flex text-gray-800 font-medium text-sm mb-2">
|
||||
{{ $t('general.select_template') }}
|
||||
<span class="text-sm text-red-500"> *</span>
|
||||
</label>
|
||||
@ -90,11 +90,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useBackupStore } from '@/scripts/stores/backup'
|
||||
import { useBackupStore } from '@/scripts/admin/stores/backup'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useDiskStore } from '@/scripts/stores/disk'
|
||||
import { useDiskStore } from '@/scripts/admin/stores/disk'
|
||||
import { required, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useCategoryStore } from '@/scripts/stores/category'
|
||||
import { useCategoryStore } from '@/scripts/admin/stores/category'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, ref } from 'vue'
|
||||
import { required, minLength, maxLength, helpers } from '@vuelidate/validators'
|
||||
@ -134,9 +134,11 @@ import { computed, onMounted, ref, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, minLength, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const companyStore = useCompanyStore()
|
||||
const modalStore = useModalStore()
|
||||
const globalStore = useGlobalStore()
|
||||
@ -227,6 +229,7 @@ async function submitCompanyData() {
|
||||
)
|
||||
|
||||
await companyStore.updateCompanyLogo(logoData)
|
||||
router.push('/admin/dashboard')
|
||||
}
|
||||
await globalStore.setIsAppLoaded(false)
|
||||
await globalStore.bootstrap()
|
||||
@ -63,7 +63,6 @@
|
||||
class="mt-1 md:mt-0"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
:label="$t('login.email')"
|
||||
:error="v$.email.$error && v$.email.$errors[0].$message"
|
||||
@ -77,6 +76,7 @@
|
||||
@input="v$.email.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
:label="$t('customers.prefix')"
|
||||
:error="v$.prefix.$error && v$.prefix.$errors[0].$message"
|
||||
@ -119,6 +119,93 @@
|
||||
</BaseInputGrid>
|
||||
</BaseTab>
|
||||
|
||||
<BaseTab :title="$t('customers.portal_access')">
|
||||
<BaseInputGrid class="col-span-5 lg:col-span-4">
|
||||
<div class="md:col-span-2">
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ $t('customers.portal_access_text') }}
|
||||
</p>
|
||||
|
||||
<BaseSwitch
|
||||
v-model="customerStore.currentCustomer.enable_portal"
|
||||
class="mt-1 flex"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<BaseInputGroup
|
||||
v-if="customerStore.currentCustomer.enable_portal"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:label="$t('customers.portal_access_url')"
|
||||
class="md:col-span-2"
|
||||
:help-text="$t('customers.portal_access_url_help')"
|
||||
>
|
||||
<CopyInputField :token="getCustomerPortalUrl" />
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
v-if="customerStore.currentCustomer.enable_portal"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:error="v$.password.$error && v$.password.$errors[0].$message"
|
||||
:label="$t('customers.password')"
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="customerStore.currentCustomer.password"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:type="isShowPassword ? 'text' : 'password'"
|
||||
name="password"
|
||||
:invalid="v$.password.$error"
|
||||
@input="v$.password.$touch()"
|
||||
>
|
||||
<template #right>
|
||||
<BaseIcon
|
||||
v-if="isShowPassword"
|
||||
name="EyeOffIcon"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
name="EyeIcon"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/> </template
|
||||
></BaseInput>
|
||||
</BaseInputGroup>
|
||||
<BaseInputGroup
|
||||
v-if="customerStore.currentCustomer.enable_portal"
|
||||
:error="
|
||||
v$.confirm_password.$error &&
|
||||
v$.confirm_password.$errors[0].$message
|
||||
"
|
||||
:content-loading="isFetchingInitialData"
|
||||
label="Confirm Password"
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="customerStore.currentCustomer.confirm_password"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:type="isShowConfirmPassword ? 'text' : 'password'"
|
||||
name="confirm_password"
|
||||
:invalid="v$.confirm_password.$error"
|
||||
@input="v$.confirm_password.$touch()"
|
||||
>
|
||||
<template #right>
|
||||
<BaseIcon
|
||||
v-if="isShowConfirmPassword"
|
||||
name="EyeOffIcon"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowConfirmPassword = !isShowConfirmPassword"
|
||||
/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
name="EyeIcon"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowConfirmPassword = !isShowConfirmPassword"
|
||||
/> </template
|
||||
></BaseInput>
|
||||
</BaseInputGroup>
|
||||
</BaseInputGrid>
|
||||
</BaseTab>
|
||||
|
||||
<BaseTab :title="$t('customers.billing_address')" class="!mt-2">
|
||||
<BaseInputGrid layout="one-column">
|
||||
<BaseInputGroup :label="$t('customers.name')">
|
||||
@ -378,22 +465,29 @@ import {
|
||||
alpha,
|
||||
url,
|
||||
helpers,
|
||||
requiredIf,
|
||||
sameAs,
|
||||
} from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useCustomerStore } from '@/scripts/stores/customer'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
import { useCustomerStore } from '@/scripts/admin/stores/customer'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import CopyInputField from '@/scripts/admin/components/CopyInputField.vue'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useRecurringInvoiceStore } from '@/scripts/admin/stores/recurring-invoice'
|
||||
|
||||
const recurringInvoiceStore = useRecurringInvoiceStore()
|
||||
const modalStore = useModalStore()
|
||||
const estimateStore = useEstimateStore()
|
||||
const customerStore = useCustomerStore()
|
||||
const companyStore = useCompanyStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const invoiceStore = useInvoiceStore()
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
let isFetchingInitialData = ref(false)
|
||||
|
||||
@ -401,71 +495,102 @@ const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const isEdit = ref(false)
|
||||
const isLoading = ref(false)
|
||||
let isShowPassword = ref(false)
|
||||
let isShowConfirmPassword = ref(false)
|
||||
|
||||
const modalActive = computed(
|
||||
() => modalStore.active && modalStore.componentName === 'CustomerModal'
|
||||
)
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
minLength: helpers.withMessage(
|
||||
t('validation.name_min_length', { count: 3 }),
|
||||
minLength(3)
|
||||
),
|
||||
},
|
||||
currency_id: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
email: {
|
||||
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||
},
|
||||
prefix: {
|
||||
minLength: helpers.withMessage(
|
||||
t('validation.name_min_length', { count: 3 }),
|
||||
minLength(3)
|
||||
),
|
||||
},
|
||||
website: {
|
||||
url: helpers.withMessage(t('validation.invalid_url'), url),
|
||||
},
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
name: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
minLength: helpers.withMessage(
|
||||
t('validation.name_min_length', { count: 3 }),
|
||||
minLength(3)
|
||||
),
|
||||
},
|
||||
currency_id: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
password: {
|
||||
required: helpers.withMessage(
|
||||
t('validation.required'),
|
||||
requiredIf(
|
||||
customerStore.currentCustomer.enable_portal == true &&
|
||||
!customerStore.currentCustomer.password_added
|
||||
)
|
||||
),
|
||||
minLength: helpers.withMessage(
|
||||
t('validation.password_min_length', { count: 8 }),
|
||||
minLength(8)
|
||||
),
|
||||
},
|
||||
confirm_password: {
|
||||
sameAsPassword: helpers.withMessage(
|
||||
t('validation.password_incorrect'),
|
||||
sameAs(customerStore.currentCustomer.password)
|
||||
),
|
||||
},
|
||||
email: {
|
||||
required: helpers.withMessage(
|
||||
t('validation.required'),
|
||||
requiredIf(customerStore.currentCustomer.enable_portal == true)
|
||||
),
|
||||
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||
},
|
||||
prefix: {
|
||||
minLength: helpers.withMessage(
|
||||
t('validation.name_min_length', { count: 3 }),
|
||||
minLength(3)
|
||||
),
|
||||
},
|
||||
website: {
|
||||
url: helpers.withMessage(t('validation.invalid_url'), url),
|
||||
},
|
||||
|
||||
billing: {
|
||||
address_street_1: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
billing: {
|
||||
address_street_1: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
address_street_2: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
},
|
||||
address_street_2: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
shipping: {
|
||||
address_street_1: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
shipping: {
|
||||
address_street_1: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
address_street_2: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
},
|
||||
address_street_2: {
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.address_maxlength', { count: 255 }),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const v$ = useVuelidate(
|
||||
rules,
|
||||
computed(() => customerStore.currentCustomer)
|
||||
)
|
||||
|
||||
const getCustomerPortalUrl = computed(() => {
|
||||
return `${window.location.origin}/${companyStore.selectedCompany.slug}/customer/login`
|
||||
})
|
||||
|
||||
function copyAddress() {
|
||||
customerStore.copyAddress()
|
||||
}
|
||||
@ -478,9 +603,15 @@ async function setInitialData() {
|
||||
}
|
||||
|
||||
async function submitCustomerData() {
|
||||
if (customerStore.currentCustomer.email === '') {
|
||||
notificationStore.showNotification({
|
||||
type: 'error',
|
||||
message: t('settings.notification.please_enter_email'),
|
||||
})
|
||||
}
|
||||
v$.value.$touch()
|
||||
|
||||
if (v$.value.$error) {
|
||||
if (v$.value.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -510,6 +641,12 @@ async function submitCustomerData() {
|
||||
) {
|
||||
estimateStore.selectCustomer(response.data.data.id)
|
||||
}
|
||||
if (
|
||||
route.name === 'recurring-invoices.create' ||
|
||||
route.name === 'recurring-invoices.edit'
|
||||
) {
|
||||
recurringInvoiceStore.selectCustomer(response.data.data.id)
|
||||
}
|
||||
closeCustomerModal()
|
||||
}
|
||||
} catch (err) {
|
||||
@ -75,8 +75,8 @@ import { computed, onMounted, ref, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, minLength, helpers, sameAs } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
|
||||
const companyStore = useCompanyStore()
|
||||
const modalStore = useModalStore()
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import ExchangeRateBulkUpdate from '@/scripts/components/currency-exchange-rate/ExchangeRateBulkUpdate.vue'
|
||||
import ExchangeRateBulkUpdate from '@/scripts/admin/components/currency-exchange-rate/ExchangeRateBulkUpdate.vue'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
@ -184,7 +184,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useExchangeRateStore } from '@/scripts/stores/exchange-rate'
|
||||
import { useExchangeRateStore } from '@/scripts/admin/stores/exchange-rate'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { debounce } from 'lodash'
|
||||
@ -60,13 +60,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useDiskStore } from '@/scripts/stores/disk'
|
||||
import { useDiskStore } from '@/scripts/admin/stores/disk'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, ref, watchEffect } from 'vue'
|
||||
import Dropbox from './disks/DropboxDisk.vue'
|
||||
import Local from './disks/LocalDisk.vue'
|
||||
import S3 from './disks/S3Disk.vue'
|
||||
import DoSpaces from './disks/DoSpacesDisk.vue'
|
||||
import Dropbox from '@/scripts/admin/components/modal-components/disks/DropboxDisk.vue'
|
||||
import Local from '@/scripts/admin/components/modal-components/disks/LocalDisk.vue'
|
||||
import S3 from '@/scripts/admin/components/modal-components/disks/S3Disk.vue'
|
||||
import DoSpaces from '@/scripts/admin/components/modal-components/disks/DoSpacesDisk.vue'
|
||||
export default {
|
||||
components: {
|
||||
Dropbox,
|
||||
@ -130,12 +130,12 @@ import {
|
||||
} from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useItemStore } from '@/scripts/stores/item'
|
||||
import { useTaxTypeStore } from '@/scripts/stores/tax-type'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useItemStore } from '@/scripts/admin/stores/item'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
|
||||
const emit = defineEmits(['newItem'])
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useItemStore } from '@/scripts/stores/item'
|
||||
import { useItemStore } from '@/scripts/admin/stores/item'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { required, minLength, maxLength, helpers } from '@vuelidate/validators'
|
||||
@ -95,7 +95,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { required, email, maxLength, helpers } from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useMailDriverStore } from '@/scripts/stores/mail-driver'
|
||||
import { useMailDriverStore } from '@/scripts/admin/stores/mail-driver'
|
||||
|
||||
let isSaving = ref(false)
|
||||
let formData = reactive({
|
||||
@ -106,10 +106,10 @@ import { required, minLength, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useNotesStore } from '@/scripts/stores/note'
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { usePaymentStore } from '@/scripts/stores/payment'
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useNotesStore } from '@/scripts/admin/stores/note'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import { usePaymentStore } from '@/scripts/admin/stores/payment'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
const notificationStore = useNotificationStore()
|
||||
@ -62,7 +62,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { usePaymentStore } from '@/scripts/stores/payment'
|
||||
import { usePaymentStore } from '@/scripts/admin/stores/payment'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, minLength, helpers } from '@vuelidate/validators'
|
||||
@ -36,7 +36,7 @@
|
||||
text-sm
|
||||
not-italic
|
||||
font-medium
|
||||
text-primary-800
|
||||
text-gray-800
|
||||
px-4
|
||||
md:px-8
|
||||
py-1.5
|
||||
@ -154,7 +154,7 @@ import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, minLength, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { useRoleStore } from '@/scripts/stores/role'
|
||||
import { useRoleStore } from '@/scripts/admin/stores/role'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
@ -42,7 +42,7 @@
|
||||
:alt="template.name"
|
||||
class="absolute z-10 w-5 h-5 text-primary-500"
|
||||
style="top: -6px; right: -5px"
|
||||
src="/img/tick.png"
|
||||
:src="getTickImage()"
|
||||
/>
|
||||
<span
|
||||
:class="[
|
||||
@ -103,6 +103,11 @@ async function chooseTemplate() {
|
||||
closeModal()
|
||||
}
|
||||
|
||||
function getTickImage() {
|
||||
const imgUrl = new URL('/img/tick.png', import.meta.url)
|
||||
return imgUrl
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modalStore.closeModal()
|
||||
|
||||
@ -138,10 +138,10 @@ import { useI18n } from 'vue-i18n'
|
||||
import { required, email, helpers } from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useMailDriverStore } from '@/scripts/stores/mail-driver'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useMailDriverStore } from '@/scripts/admin/stores/mail-driver'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
const estimateStore = useEstimateStore()
|
||||
@ -148,13 +148,13 @@
|
||||
<script setup>
|
||||
import { ref, computed, reactive, onMounted } from 'vue'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { required, email, helpers } from '@vuelidate/validators'
|
||||
import { useMailDriverStore } from '@/scripts/stores/mail-driver'
|
||||
import { useMailDriverStore } from '@/scripts/admin/stores/mail-driver'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
const companyStore = useCompanyStore()
|
||||
@ -150,11 +150,11 @@ import { useI18n } from 'vue-i18n'
|
||||
import { required, email, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { ref, reactive, computed, watch, watchEffect } from 'vue'
|
||||
import { usePaymentStore } from '@/scripts/stores/payment'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { usePaymentStore } from '@/scripts/admin/stores/payment'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useMailDriverStore } from '@/scripts/stores/mail-driver'
|
||||
import { useMailDriverStore } from '@/scripts/admin/stores/mail-driver'
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
|
||||
const paymentStore = usePaymentStore()
|
||||
@ -128,16 +128,16 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useTaxTypeStore } from '@/scripts/stores/tax-type'
|
||||
import { useTaxTypeStore } from '@/scripts/admin/stores/tax-type'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useEstimateStore } from '@/scripts/stores/estimate'
|
||||
import { useInvoiceStore } from '@/scripts/stores/invoice'
|
||||
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
|
||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Guid from 'guid'
|
||||
import TaxStub from '@/scripts/stub/tax'
|
||||
import TaxStub from '@/scripts/admin/stub/abilities'
|
||||
import {
|
||||
required,
|
||||
minLength,
|
||||
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<BaseModal :show="modalActive" @close="closeModal" @open="setAddress">
|
||||
<template #header>
|
||||
<div class="flex justify-between w-full">
|
||||
<div class="flex flex-col">
|
||||
{{ modalStore.title }}
|
||||
|
||||
<p class="text-sm text-gray-500 mt-1">
|
||||
{{ modalStore.content }}
|
||||
</p>
|
||||
</div>
|
||||
<BaseIcon
|
||||
name="XIcon"
|
||||
class="h-6 w-6 text-gray-500 cursor-pointer"
|
||||
@click="closeModal"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<form @submit.prevent="saveCustomerAddress">
|
||||
<div class="p-4 sm:p-6">
|
||||
<BaseInputGrid layout="one-column">
|
||||
<BaseInputGroup
|
||||
required
|
||||
:error="v$.state.$error && v$.state.$errors[0].$message"
|
||||
:label="$t('customers.state')"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="address.state"
|
||||
type="text"
|
||||
name="shippingState"
|
||||
class="mt-1 md:mt-0"
|
||||
:invalid="v$.state.$error"
|
||||
@input="v$.state.$touch()"
|
||||
:placeholder="$t('settings.taxations.state_placeholder')"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
required
|
||||
:error="v$.city.$error && v$.city.$errors[0].$message"
|
||||
:label="$t('customers.city')"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="address.city"
|
||||
type="text"
|
||||
name="shippingCity"
|
||||
class="mt-1 md:mt-0"
|
||||
:invalid="v$.city.$error"
|
||||
@input="v$.city.$touch()"
|
||||
:placeholder="$t('settings.taxations.city_placeholder')"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
required
|
||||
:error="
|
||||
v$.address_street_1.$error &&
|
||||
v$.address_street_1.$errors[0].$message
|
||||
"
|
||||
:label="$t('customers.address')"
|
||||
>
|
||||
<BaseTextarea
|
||||
v-model="address.address_street_1"
|
||||
rows="2"
|
||||
cols="50"
|
||||
class="mt-1 md:mt-0"
|
||||
:invalid="v$.address_street_1.$error"
|
||||
@input="v$.address_street_1.$touch()"
|
||||
:placeholder="$t('settings.taxations.address_placeholder')"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
required
|
||||
:error="v$.zip.$error && v$.zip.$errors[0].$message"
|
||||
:label="$t('customers.zip_code')"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="address.zip"
|
||||
:invalid="v$.zip.$error"
|
||||
@input="v$.zip.$touch()"
|
||||
type="text"
|
||||
class="mt-1 md:mt-0"
|
||||
:placeholder="$t('settings.taxations.zip_placeholder')"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
</BaseInputGrid>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
||||
>
|
||||
<BaseButton
|
||||
class="mr-3 text-sm"
|
||||
type="button"
|
||||
variant="primary-outline"
|
||||
@click="closeModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</BaseButton>
|
||||
|
||||
<BaseButton :loading="isLoading" variant="primary" type="submit">
|
||||
<template #left="slotProps">
|
||||
<BaseIcon
|
||||
v-if="!isLoading"
|
||||
name="SaveIcon"
|
||||
:class="slotProps.class"
|
||||
/>
|
||||
</template>
|
||||
{{ $t('general.save') }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</BaseModal>
|
||||
</template>
|
||||
|
||||
<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'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { helpers, required } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
const address = reactive({
|
||||
state: '',
|
||||
city: '',
|
||||
address_street_1: '',
|
||||
zip: '',
|
||||
})
|
||||
|
||||
const isLoading = ref(false)
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
const modalActive = computed(
|
||||
() => modalStore.active && modalStore.componentName === 'TaxationAddressModal'
|
||||
)
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
state: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
city: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
address_street_1: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
zip: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const v$ = useVuelidate(
|
||||
rules,
|
||||
computed(() => address)
|
||||
)
|
||||
|
||||
async function saveCustomerAddress() {
|
||||
v$.value.$touch()
|
||||
|
||||
if (v$.value.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
let data = {
|
||||
address,
|
||||
}
|
||||
if (modalStore.id) {
|
||||
data.customer_id = modalStore.id
|
||||
}
|
||||
// replace '/n' with empty string
|
||||
address.address_street_1 = address.address_street_1.replace(
|
||||
/(\r\n|\n|\r)/gm,
|
||||
''
|
||||
)
|
||||
|
||||
isLoading.value = true
|
||||
await taxTypeStore
|
||||
.fetchSalesTax(data)
|
||||
.then((res) => {
|
||||
isLoading.value = false
|
||||
emit('addTax', res.data.data)
|
||||
closeModal()
|
||||
})
|
||||
.catch((e) => {
|
||||
isLoading.value = false
|
||||
})
|
||||
}
|
||||
const emit = defineEmits(['addTax'])
|
||||
|
||||
function setAddress() {
|
||||
address.state = modalStore?.data?.state
|
||||
address.city = modalStore?.data?.city
|
||||
address.address_street_1 = modalStore?.data?.address_street_1
|
||||
address.zip = modalStore?.data?.zip
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modalStore.closeModal()
|
||||
}
|
||||
</script>
|
||||
@ -219,7 +219,7 @@ import moment from 'moment'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { required, numeric, helpers } from '@vuelidate/validators'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useCustomFieldStore } from '@/scripts/stores/custom-field'
|
||||
import { useCustomFieldStore } from '@/scripts/admin/stores/custom-field'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
@ -163,7 +163,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useDiskStore } from '@/scripts/stores/disk'
|
||||
import { useDiskStore } from '@/scripts/admin/stores/disk'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, onBeforeUnmount, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@ -143,7 +143,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useDiskStore } from '@/scripts/stores/disk'
|
||||
import { useDiskStore } from '@/scripts/admin/stores/disk'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { reactive, ref, computed, onBeforeUnmount } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@ -74,7 +74,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useDiskStore } from '@/scripts/stores/disk'
|
||||
import { useDiskStore } from '@/scripts/admin/stores/disk'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, onBeforeUnmount, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@ -145,7 +145,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useDiskStore } from '@/scripts/stores/disk'
|
||||
import { useDiskStore } from '@/scripts/admin/stores/disk'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { computed, onBeforeUnmount, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
<main
|
||||
class="
|
||||
mt-16
|
||||
pt-16
|
||||
pb-16
|
||||
h-screen h-screen-ios
|
||||
overflow-y-auto
|
||||
@ -28,18 +28,18 @@
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useExchangeRateStore } from '@/scripts/stores/exchange-rate'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import { useExchangeRateStore } from '@/scripts/admin/stores/exchange-rate'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
|
||||
import SiteHeader from '@/scripts/layouts/partials/TheSiteHeader.vue'
|
||||
import SiteSidebar from '@/scripts/layouts/partials/TheSiteSidebar.vue'
|
||||
import SiteHeader from '@/scripts/admin/layouts/partials/TheSiteHeader.vue'
|
||||
import SiteSidebar from '@/scripts/admin/layouts/partials/TheSiteSidebar.vue'
|
||||
import NotificationRoot from '@/scripts/components/notifications/NotificationRoot.vue'
|
||||
import ExchangeRateBulkUpdateModal from '@/scripts/components/modal-components/ExchangeRateBulkUpdateModal.vue'
|
||||
import ExchangeRateBulkUpdateModal from '@/scripts/admin/components/modal-components/ExchangeRateBulkUpdateModal.vue'
|
||||
|
||||
const globalStore = useGlobalStore()
|
||||
const route = useRoute()
|
||||
@ -28,11 +28,7 @@
|
||||
"
|
||||
>
|
||||
<div class="w-full">
|
||||
<img
|
||||
src="/img/crater-logo.png"
|
||||
class="block w-48 h-auto max-w-full mb-32 text-primary-400"
|
||||
alt="Crater Logo"
|
||||
/>
|
||||
<MainLogo class="block w-48 h-auto max-w-full mb-32 text-primary-500" />
|
||||
|
||||
<router-view />
|
||||
|
||||
@ -69,9 +65,18 @@
|
||||
lg:col-span-8
|
||||
md:flex
|
||||
content-box
|
||||
overflow-hidden
|
||||
"
|
||||
>
|
||||
<div class="pl-20 xl:pl-0">
|
||||
<LoginBackground class="absolute h-full w-full" />
|
||||
|
||||
<LoginPlanetCrater
|
||||
class="absolute z-10 top-0 right-0 h-[300px] w-[420px]"
|
||||
/>
|
||||
|
||||
<LoginBackgroundOverlay class="absolute h-full w-full right-[7.5%]" />
|
||||
|
||||
<div class="pl-20 xl:pl-0 relative z-50">
|
||||
<h1
|
||||
class="
|
||||
hidden
|
||||
@ -106,46 +111,32 @@
|
||||
invoices & estimates. <br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="absolute z-50 w-full bg-no-repeat content-bottom" />
|
||||
|
||||
<LoginBottomVector
|
||||
class="
|
||||
absolute
|
||||
z-50
|
||||
w-full
|
||||
bg-no-repeat
|
||||
content-bottom
|
||||
h-[15vw]
|
||||
lg:h-[22vw]
|
||||
right-[32%]
|
||||
bottom-0
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import NotificationRoot from '@/scripts/components/notifications/NotificationRoot.vue'
|
||||
import MainLogo from '@/scripts/components/icons/MainLogo.vue'
|
||||
import LoginBackground from '@/scripts/components/svg/LoginBackground.vue'
|
||||
import LoginPlanetCrater from '@/scripts/components/svg/LoginPlanetCrater.vue'
|
||||
import LoginBottomVector from '@/scripts/components/svg/LoginBottomVector.vue'
|
||||
import LoginBackgroundOverlay from '@/scripts/components/svg/LoginBackgroundOverlay.vue'
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-box {
|
||||
background-image: url('/img/login/login-vector1.svg');
|
||||
}
|
||||
.content-bottom {
|
||||
background-image: url('/img/login/login-vector3.svg');
|
||||
background-size: 100% 100%;
|
||||
height: 300px;
|
||||
right: 32%;
|
||||
bottom: 0;
|
||||
}
|
||||
.content-box::before {
|
||||
background-image: url('/img/login/frame.svg');
|
||||
content: '';
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
height: 300px;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 420px;
|
||||
z-index: 1;
|
||||
}
|
||||
.content-box::after {
|
||||
background-image: url('/img/login/login-vector2.svg');
|
||||
content: '';
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
right: 7.5%;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
@ -1,23 +1,58 @@
|
||||
<template>
|
||||
<header
|
||||
class="fixed top-0 left-0 z-20 flex items-center justify-between w-full px-4 py-3 md:h-16 md:px-8 bg-gradient-to-r from-primary-500 to-primary-400"
|
||||
class="
|
||||
fixed
|
||||
top-0
|
||||
left-0
|
||||
z-20
|
||||
flex
|
||||
items-center
|
||||
justify-between
|
||||
w-full
|
||||
px-4
|
||||
py-3
|
||||
md:h-16 md:px-8
|
||||
bg-gradient-to-r
|
||||
from-primary-500
|
||||
to-primary-400
|
||||
"
|
||||
>
|
||||
<router-link
|
||||
to="/admin/dashboard"
|
||||
class="float-none text-lg not-italic font-black tracking-wider text-white brand-main md:float-left font-base hidden md:block"
|
||||
class="
|
||||
float-none
|
||||
text-lg
|
||||
not-italic
|
||||
font-black
|
||||
tracking-wider
|
||||
text-white
|
||||
brand-main
|
||||
md:float-left
|
||||
font-base
|
||||
hidden
|
||||
md:block
|
||||
"
|
||||
>
|
||||
<img
|
||||
id="logo-white"
|
||||
src="/img/logo-white.png"
|
||||
alt="Crater Logo"
|
||||
class="h-6"
|
||||
/>
|
||||
<MainLogo class="h-6" light-color="white" dark-color="white" />
|
||||
</router-link>
|
||||
|
||||
<!-- toggle button-->
|
||||
<div
|
||||
:class="{ 'is-active': globalStore.isSidebarOpen }"
|
||||
class="flex float-left p-1 overflow-visible text-sm ease-linear bg-white border-0 rounded cursor-pointer md:hidden md:ml-0 hover:bg-gray-100"
|
||||
class="
|
||||
flex
|
||||
float-left
|
||||
p-1
|
||||
overflow-visible
|
||||
text-sm
|
||||
ease-linear
|
||||
bg-white
|
||||
border-0
|
||||
rounded
|
||||
cursor-pointer
|
||||
md:hidden md:ml-0
|
||||
hover:bg-gray-100
|
||||
"
|
||||
@click.prevent="onToggle"
|
||||
>
|
||||
<BaseIcon name="MenuIcon" class="!w-6 !h-6 text-gray-500" />
|
||||
@ -31,7 +66,18 @@
|
||||
<BaseDropdown width-class="w-48">
|
||||
<template #activator>
|
||||
<div
|
||||
class="flex items-center justify-center w-8 h-8 ml-2 text-sm text-black bg-white rounded md:h-9 md:w-9"
|
||||
class="
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
w-8
|
||||
h-8
|
||||
ml-2
|
||||
text-sm text-black
|
||||
bg-white
|
||||
rounded
|
||||
md:h-9 md:w-9
|
||||
"
|
||||
>
|
||||
<BaseIcon name="PlusIcon" class="w-5 h-5 text-gray-600" />
|
||||
</div>
|
||||
@ -117,7 +163,7 @@
|
||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Logout
|
||||
{{ $t('navigation.logout') }}
|
||||
</BaseDropdownItem>
|
||||
</BaseDropdown>
|
||||
</li>
|
||||
@ -126,14 +172,17 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useAuthStore } from '@/scripts/stores/auth'
|
||||
import { useAuthStore } from '@/scripts/admin/stores/auth'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
import { useUserStore } from '@/scripts/stores/user'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
|
||||
import CompanySwitcher from '@/scripts/components/CompanySwitcher.vue'
|
||||
import GlobalSearchBar from '@/scripts/components/GlobalSearchBar.vue'
|
||||
import abilities from '@/scripts/stub/abilities'
|
||||
import MainLogo from '@/scripts/components/icons/MainLogo.vue'
|
||||
|
||||
import abilities from '@/scripts/admin/stub/abilities'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const userStore = useUserStore()
|
||||
@ -20,10 +20,10 @@
|
||||
|
||||
<TransitionChild
|
||||
as="template"
|
||||
enter="transition ease-in-out duration-300 transform"
|
||||
enter="transition ease-in-out duration-300"
|
||||
enter-from="-translate-x-full"
|
||||
enter-to="translate-x-0"
|
||||
leave="transition ease-in-out duration-300 transform"
|
||||
leave="transition ease-in-out duration-300"
|
||||
leave-from="translate-x-0"
|
||||
leave-to="-translate-x-full"
|
||||
>
|
||||
@ -64,9 +64,8 @@
|
||||
</div>
|
||||
</TransitionChild>
|
||||
<div class="flex-1 h-0 pt-5 pb-4 overflow-y-auto">
|
||||
<div class="flex items-center flex-shrink-0 px-4 mb-10">
|
||||
<img
|
||||
src="/img/crater-logo.png"
|
||||
<div class="flex items-center shrink-0 px-4 mb-10">
|
||||
<MainLogo
|
||||
class="block h-auto max-w-full w-36 text-primary-400"
|
||||
alt="Crater Logo"
|
||||
/>
|
||||
@ -95,7 +94,7 @@
|
||||
hasActiveUrl(item.link)
|
||||
? 'text-primary-500 '
|
||||
: 'text-gray-400',
|
||||
'mr-4 flex-shrink-0 h-5 w-5',
|
||||
'mr-4 shrink-0 h-5 w-5',
|
||||
]"
|
||||
@click="globalStore.setSidebarVisibility(false)"
|
||||
/>
|
||||
@ -105,7 +104,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
<div class="flex-shrink-0 w-14">
|
||||
<div class="shrink-0 w-14">
|
||||
<!-- Force sidebar to shrink to fit close icon -->
|
||||
</div>
|
||||
</Dialog>
|
||||
@ -148,7 +147,7 @@
|
||||
hasActiveUrl(item.link)
|
||||
? 'text-primary-500 group-hover:text-primary-500 '
|
||||
: 'text-gray-400 group-hover:text-black',
|
||||
'mr-4 flex-shrink-0 h-5 w-5 ',
|
||||
'mr-4 shrink-0 h-5 w-5 ',
|
||||
]"
|
||||
/>
|
||||
|
||||
@ -159,6 +158,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import MainLogo from '@/scripts/components/icons/MainLogo.vue'
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogOverlay,
|
||||
@ -167,7 +168,7 @@ import {
|
||||
} from '@headlessui/vue'
|
||||
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
|
||||
const route = useRoute()
|
||||
const globalStore = useGlobalStore()
|
||||
@ -1,14 +1,11 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useResetStore } from './reset'
|
||||
import router from '@/scripts/router'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useAuthStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
const resetStore = useResetStore()
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'auth',
|
||||
@ -52,19 +49,18 @@ export const useAuthStore = (useWindow = false) => {
|
||||
.get('/auth/logout')
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: 'Logged out successfully.',
|
||||
})
|
||||
|
||||
router.push('/login')
|
||||
resetStore.clearPinia()
|
||||
window.router.push('/login')
|
||||
// resetStore.clearPinia()
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
router.push('/')
|
||||
window.router.push('/')
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useBackupStore = (useWindow = false) => {
|
||||
@ -56,7 +56,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
|
||||
addCategory(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios
|
||||
axios
|
||||
.post('/api/v1/categories', data)
|
||||
.then((response) => {
|
||||
this.categories.push(response.data.data)
|
||||
@ -76,7 +76,7 @@ export const useCategoryStore = (useWindow = false) => {
|
||||
|
||||
updateCategory(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios
|
||||
axios
|
||||
.put(`/api/v1/categories/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
@ -1,8 +1,8 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import Ls from '../services/ls'
|
||||
import Ls from '@/scripts/services/ls'
|
||||
|
||||
export const useCompanyStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
@ -1,8 +1,8 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import customFieldStub from '@/scripts/stub/custom-field'
|
||||
import utilities from '../helpers/utilities'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import customFieldStub from '@/scripts/admin/stub/custom-field'
|
||||
import utilities from '@/scripts/helpers/utilities'
|
||||
import { util } from 'prettier'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
@ -3,10 +3,10 @@ import { defineStore } from 'pinia'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useCompanyStore } from '@/scripts/stores/company'
|
||||
import addressStub from '@/scripts/stub/address.js'
|
||||
import customerStub from '@/scripts/stub/customer'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import addressStub from '@/scripts/admin/stub/address.js'
|
||||
import customerStub from '@/scripts/admin/stub/customer'
|
||||
|
||||
export const useCustomerStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
@ -115,6 +115,7 @@ export const useCustomerStore = (useWindow = false) => {
|
||||
.get(`/api/v1/customers/${id}`)
|
||||
.then((response) => {
|
||||
Object.assign(this.currentCustomer, response.data.data)
|
||||
|
||||
this.setAddressStub(response.data.data)
|
||||
resolve(response)
|
||||
})
|
||||
@ -1,5 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useGlobalStore } from '@/scripts/stores/global'
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useDashboardStore = (useWindow = false) => {
|
||||
@ -6,7 +6,7 @@ import { defineStore } from 'pinia'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useCompanyStore } from './company'
|
||||
import { useCustomerStore } from './customer'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useItemStore } from './item'
|
||||
import { useTaxTypeStore } from './tax-type'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
@ -146,12 +146,31 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
addSalesTaxUs() {
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
let salesTax = { ...taxStub }
|
||||
let found = this.newEstimate.taxes.find((_t) => _t.name === 'Sales Tax' && _t.type === 'MODULE')
|
||||
if (found) {
|
||||
for (const key in found) {
|
||||
if (Object.prototype.hasOwnProperty.call(salesTax, key)) {
|
||||
salesTax[key] = found[key]
|
||||
}
|
||||
}
|
||||
salesTax.id = found.tax_type_id
|
||||
console.log(salesTax, 'salesTax');
|
||||
|
||||
taxTypeStore.taxTypes.push(salesTax)
|
||||
console.log(taxTypeStore.taxTypes);
|
||||
}
|
||||
},
|
||||
|
||||
sendEstimate(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
@ -493,12 +512,16 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
if (!isEdit) {
|
||||
this.newEstimate.tax_per_item =
|
||||
companyStore.selectedCompanySettings.tax_per_item
|
||||
this.newEstimate.sales_tax_type = companyStore.selectedCompanySettings.sales_tax_type
|
||||
this.newEstimate.sales_tax_address_type = companyStore.selectedCompanySettings.sales_tax_address_type
|
||||
this.newEstimate.discount_per_item =
|
||||
companyStore.selectedCompanySettings.discount_per_item
|
||||
this.newEstimate.estimate_date = moment().format('YYYY-MM-DD')
|
||||
this.newEstimate.expiry_date = moment()
|
||||
.add(7, 'days')
|
||||
.format('YYYY-MM-DD')
|
||||
if (companyStore.selectedCompanySettings.estimate_set_expiry_date_automatically === 'YES') {
|
||||
this.newEstimate.expiry_date = moment()
|
||||
.add(companyStore.selectedCompanySettings.estimate_expiry_date_days, 'days')
|
||||
.format('YYYY-MM-DD')
|
||||
}
|
||||
} else {
|
||||
editActions = [this.fetchEstimate(route.params.id)]
|
||||
}
|
||||
@ -525,6 +548,9 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
this.setTemplate(this.templates[0].name)
|
||||
}
|
||||
|
||||
if (isEdit) {
|
||||
this.addSalesTaxUs()
|
||||
}
|
||||
this.isFetchingInitialSettings = false
|
||||
})
|
||||
.catch((err) => {
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useExchangeRateStore = (useWindow = false) => {
|
||||
@ -1,8 +1,8 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import { useNotificationStore } from './notification'
|
||||
import expenseStub from '@/scripts/stub/expense'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import expenseStub from '@/scripts/admin/stub/expense'
|
||||
import utils from '@/scripts/helpers/utilities'
|
||||
|
||||
export const useExpenseStore = (useWindow = false) => {
|
||||
@ -59,7 +59,8 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
Object.assign(this.currentExpense, response.data.data)
|
||||
this.currentExpense.selectedCurrency = response.data.data.currency
|
||||
this.currentExpense.selectedCurrency =
|
||||
response.data.data.currency
|
||||
|
||||
if (response.data.data.attachment_receipt) {
|
||||
if (
|
||||
@ -1,7 +1,9 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useCompanyStore } from './company'
|
||||
import { useUserStore } from './user'
|
||||
import axios from 'axios'
|
||||
import { useModuleStore } from './module'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import _ from 'lodash'
|
||||
|
||||
@ -14,6 +16,7 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
state: () => ({
|
||||
// Global Configuration
|
||||
config: null,
|
||||
globalSettings: null,
|
||||
|
||||
// Global Lists
|
||||
timeZones: [],
|
||||
@ -49,11 +52,13 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
.then((response) => {
|
||||
const companyStore = useCompanyStore()
|
||||
const userStore = useUserStore()
|
||||
const moduleStore = useModuleStore()
|
||||
|
||||
this.mainMenu = response.data.main_menu
|
||||
this.settingMenu = response.data.setting_menu
|
||||
|
||||
this.config = response.data.config
|
||||
this.globalSettings = response.data.global_settings
|
||||
|
||||
// user store
|
||||
userStore.currentUser = response.data.current_user
|
||||
@ -61,8 +66,12 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
response.data.current_user_settings
|
||||
userStore.currentAbilities = response.data.current_user_abilities
|
||||
|
||||
// company store
|
||||
companyStore.companies = response.data.companies
|
||||
// Module store
|
||||
moduleStore.apiToken = response.data.global_settings.api_token
|
||||
moduleStore.enableModules = response.data.modules
|
||||
|
||||
// company store
|
||||
companyStore.companies = response.data.companies
|
||||
companyStore.selectedCompany = response.data.current_company
|
||||
companyStore.setSelectedCompany(response.data.current_company)
|
||||
companyStore.selectedCompanySettings =
|
||||
@ -204,6 +213,31 @@ export const useGlobalStore = (useWindow = false) => {
|
||||
setIsAppLoaded(isAppLoaded) {
|
||||
this.isAppLoaded = isAppLoaded
|
||||
},
|
||||
|
||||
updateGlobalSettings({ data, message }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post('/api/v1/settings', data)
|
||||
.then((response) => {
|
||||
Object.assign(this.globalSettings, data.settings)
|
||||
|
||||
if (message) {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t(message),
|
||||
})
|
||||
}
|
||||
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
})()
|
||||
}
|
||||
@ -9,7 +9,7 @@ import invoiceItemStub from '../stub/invoice-item'
|
||||
import taxStub from '../stub/tax'
|
||||
import invoiceStub from '../stub/invoice'
|
||||
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { useCustomerStore } from './customer'
|
||||
import { useTaxTypeStore } from './tax-type'
|
||||
import { useCompanyStore } from './company'
|
||||
@ -143,6 +143,21 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
})
|
||||
},
|
||||
|
||||
addSalesTaxUs() {
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
let salesTax = { ...taxStub }
|
||||
let found = this.newInvoice.taxes.find((_t) => _t.name === 'Sales Tax' && _t.type === 'MODULE')
|
||||
if (found) {
|
||||
for (const key in found) {
|
||||
if (Object.prototype.hasOwnProperty.call(salesTax, key)) {
|
||||
salesTax[key] = found[key]
|
||||
}
|
||||
}
|
||||
salesTax.id = found.tax_type_id
|
||||
taxTypeStore.taxTypes.push(salesTax)
|
||||
}
|
||||
},
|
||||
|
||||
sendInvoice(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
@ -446,12 +461,16 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
if (!isEdit) {
|
||||
this.newInvoice.tax_per_item =
|
||||
companyStore.selectedCompanySettings.tax_per_item
|
||||
this.newInvoice.sales_tax_type = companyStore.selectedCompanySettings.sales_tax_type
|
||||
this.newInvoice.sales_tax_address_type = companyStore.selectedCompanySettings.sales_tax_address_type
|
||||
this.newInvoice.discount_per_item =
|
||||
companyStore.selectedCompanySettings.discount_per_item
|
||||
this.newInvoice.invoice_date = moment().format('YYYY-MM-DD')
|
||||
this.newInvoice.due_date = moment()
|
||||
.add(7, 'days')
|
||||
.format('YYYY-MM-DD')
|
||||
if (companyStore.selectedCompanySettings.invoice_set_due_date_automatically === 'YES') {
|
||||
this.newInvoice.due_date = moment()
|
||||
.add(companyStore.selectedCompanySettings.invoice_due_date_days, 'days')
|
||||
.format('YYYY-MM-DD')
|
||||
}
|
||||
} else {
|
||||
editActions = [this.fetchInvoice(route.params.id)]
|
||||
}
|
||||
@ -478,6 +497,9 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
this.setTemplate(this.templates[0].name)
|
||||
}
|
||||
}
|
||||
if (isEdit) {
|
||||
this.addSalesTaxUs()
|
||||
}
|
||||
|
||||
this.isFetchingInitialSettings = false
|
||||
})
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useItemStore = (useWindow = false) => {
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useMailDriverStore = (useWindow = false) => {
|
||||
132
resources/scripts/admin/stores/module.js
Normal file
132
resources/scripts/admin/stores/module.js
Normal file
@ -0,0 +1,132 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
|
||||
export const useModuleStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'modules',
|
||||
|
||||
state: () => ({
|
||||
currentModule: {},
|
||||
modules: [],
|
||||
apiToken: null,
|
||||
currentUser: {
|
||||
api_token: null,
|
||||
},
|
||||
enableModules: []
|
||||
}),
|
||||
|
||||
getters: {
|
||||
salesTaxUSEnabled: (state) => (state.enableModules.includes('SalesTaxUS')),
|
||||
},
|
||||
|
||||
actions: {
|
||||
fetchModules(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/modules`)
|
||||
.then((response) => {
|
||||
this.modules = response.data.data
|
||||
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
fetchModule(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/modules/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data.error === 'invalid_token') {
|
||||
this.currentModule = {},
|
||||
this.modules = [],
|
||||
this.apiToken = null,
|
||||
this.currentUser.api_token = null,
|
||||
window.router.push('/admin/modules')
|
||||
} else {
|
||||
this.currentModule = response.data
|
||||
}
|
||||
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
checkApiToken(token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/modules/check?api_token=${token}`)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
if (response.data.error === 'invalid_token') {
|
||||
notificationStore.showNotification({
|
||||
type: 'error',
|
||||
message: global.t('modules.invalid_api_token'),
|
||||
})
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
disableModule(module) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(`/api/v1/modules/${module}/disable`)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
if (response.data.success) {
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t('modules.module_disabled'),
|
||||
})
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
enableModule(module) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(`/api/v1/modules/${module}/enable`)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
if (response.data.success) {
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t('modules.module_enabled'),
|
||||
})
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
})()
|
||||
}
|
||||
@ -3,7 +3,7 @@ import moment from 'moment'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useCompanyStore } from './company'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import paymentStub from '../stub/payment'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
@ -22,6 +22,19 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
selectedPayments: [],
|
||||
selectedNote: null,
|
||||
showExchangeRate: false,
|
||||
drivers: [],
|
||||
providers: [],
|
||||
|
||||
paymentProviders: {
|
||||
id: null,
|
||||
name: '',
|
||||
driver: '',
|
||||
active: false,
|
||||
settings: {
|
||||
key: '',
|
||||
secret: '',
|
||||
},
|
||||
},
|
||||
|
||||
currentPayment: {
|
||||
...paymentStub,
|
||||
@ -36,6 +49,10 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
isFetchingInitialData: false,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isEdit: (state) => (state.paymentProviders.id ? true : false),
|
||||
},
|
||||
|
||||
actions: {
|
||||
fetchPaymentInitialData(isEdit) {
|
||||
const companyStore = useCompanyStore()
|
||||
@ -76,6 +93,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
fetchPayments(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
@ -106,6 +124,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
addPayment(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
@ -281,7 +300,7 @@ export const usePaymentStore = (useWindow = false) => {
|
||||
|
||||
getNextNumber(params, setState = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios
|
||||
axios
|
||||
.get(`/api/v1/next-number?key=payment`, { params })
|
||||
.then((response) => {
|
||||
if (setState) {
|
||||
@ -1,6 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import recurringInvoiceStub from '@/scripts/stub/recurring-invoice'
|
||||
import recurringInvoiceItemStub from '@/scripts/stub/recurring-invoice-item'
|
||||
import axios from 'axios'
|
||||
import recurringInvoiceStub from '@/scripts/admin/stub/recurring-invoice'
|
||||
import recurringInvoiceItemStub from '@/scripts/admin/stub/recurring-invoice-item'
|
||||
import TaxStub from '../stub/tax'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useCompanyStore } from './company'
|
||||
@ -12,7 +13,7 @@ import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import moment from 'moment'
|
||||
import _ from 'lodash'
|
||||
import { useInvoiceStore } from './invoice'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
|
||||
export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
@ -351,6 +352,8 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
companyStore.selectedCompanySettings.tax_per_item
|
||||
this.newRecurringInvoice.discount_per_item =
|
||||
companyStore.selectedCompanySettings.discount_per_item
|
||||
this.newRecurringInvoice.sales_tax_type = companyStore.selectedCompanySettings.sales_tax_type
|
||||
this.newRecurringInvoice.sales_tax_address_type = companyStore.selectedCompanySettings.sales_tax_address_type
|
||||
this.newRecurringInvoice.starts_at = moment().format('YYYY-MM-DD')
|
||||
this.newRecurringInvoice.next_invoice_date = moment()
|
||||
.add(7, 'days')
|
||||
@ -386,14 +389,32 @@ export const useRecurringInvoiceStore = (useWindow = false) => {
|
||||
|
||||
this.setTemplate(res5?.data?.data?.template_name)
|
||||
}
|
||||
|
||||
if (isEdit) {
|
||||
this.addSalesTaxUs()
|
||||
}
|
||||
this.isFetchingInitialSettings = false
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
handleError(err)
|
||||
})
|
||||
},
|
||||
|
||||
addSalesTaxUs() {
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
let salesTax = { ...TaxStub }
|
||||
let found = this.newRecurringInvoice.taxes.find((_t) => _t.name === 'Sales Tax' && _t.type === 'MODULE')
|
||||
if (found) {
|
||||
for (const key in found) {
|
||||
if (Object.prototype.hasOwnProperty.call(salesTax, key)) {
|
||||
salesTax[key] = found[key]
|
||||
}
|
||||
}
|
||||
salesTax.id = found.tax_type_id
|
||||
taxTypeStore.taxTypes.push(salesTax)
|
||||
}
|
||||
},
|
||||
|
||||
setTemplate(data) {
|
||||
this.newRecurringInvoice.template_name = data
|
||||
},
|
||||
@ -6,7 +6,7 @@ import { useCompanyStore } from './company'
|
||||
import { useCustomFieldStore } from './custom-field'
|
||||
import { useCustomerStore } from './customer'
|
||||
import { useDashboardStore } from './dashboard'
|
||||
import { useDialogStore } from './dialog'
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useDiskStore } from './disk'
|
||||
import { useEstimateStore } from './estimate'
|
||||
import { useExchangeRateStore } from './exchange-rate'
|
||||
@ -16,9 +16,9 @@ import { useInstallationStore } from './installation'
|
||||
import { useInvoiceStore } from './invoice'
|
||||
import { useItemStore } from './item'
|
||||
import { useMailDriverStore } from './mail-driver'
|
||||
import { useModalStore } from './modal'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useNotesStore } from './note'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { usePaymentStore } from './payment'
|
||||
import { useRecurringInvoiceStore } from './recurring-invoice'
|
||||
import { useRoleStore } from './role'
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import _ from 'lodash'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useTaxTypeStore = (useWindow = false) => {
|
||||
@ -55,7 +55,7 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
|
||||
fetchTaxType(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios
|
||||
axios
|
||||
.get(`/api/v1/tax-types/${id}`)
|
||||
.then((response) => {
|
||||
this.currentTaxType = response.data.data
|
||||
@ -113,9 +113,31 @@ export const useTaxTypeStore = (useWindow = false) => {
|
||||
})
|
||||
},
|
||||
|
||||
fetchSalesTax(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post('/api/m/sales-tax-us/current-tax', data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
let pos = this.taxTypes.findIndex(
|
||||
(_t) => _t.name === 'SalesTaxUs'
|
||||
)
|
||||
pos > -1 ? this.taxTypes.splice(pos, 1) : ''
|
||||
this.taxTypes.push({ ...response.data.data, tax_type_id: response.data.data.id })
|
||||
}
|
||||
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
deleteTaxType(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios
|
||||
axios
|
||||
.delete(`/api/v1/tax-types/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data.success) {
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useUserStore = (useWindow = false) => {
|
||||
@ -1,7 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from './notification'
|
||||
import { handleError } from '../helpers/error-handling'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
|
||||
export const useUsersStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
@ -190,7 +190,7 @@ export const useUsersStore = (useWindow = false) => {
|
||||
|
||||
searchUsers(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios
|
||||
axios
|
||||
.get(`/api/v1/search`, { params })
|
||||
.then((response) => {
|
||||
this.userList = response.data.users.data
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user