v6 update

This commit is contained in:
Mohit Panjwani
2022-01-10 16:06:17 +05:30
parent b770e6277f
commit bdea879273
722 changed files with 19047 additions and 9186 deletions

View File

@ -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
View 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;
}

View File

@ -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 {

View 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 },
]

View 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>

View File

@ -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: {

View File

@ -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')

View File

@ -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'

View File

@ -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'

View File

@ -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: {

View File

@ -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: {

View File

@ -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: {

View File

@ -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: {

View File

@ -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: {

View File

@ -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)
)
}

View File

@ -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: {

View File

@ -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: {

View File

@ -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: {

View File

@ -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({

View File

@ -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: {

View File

@ -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({

View File

@ -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: {

View File

@ -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: {

View File

@ -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({

View File

@ -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: {

View File

@ -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'

View File

@ -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

View File

@ -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)

View File

@ -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: {

View File

@ -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>

View File

@ -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: {

View File

@ -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>

View File

@ -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'

View File

@ -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'

View File

@ -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()

View File

@ -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) {

View File

@ -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()

View File

@ -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()

View File

@ -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'

View File

@ -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,

View File

@ -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'])

View File

@ -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'

View File

@ -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({

View File

@ -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()

View File

@ -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'

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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,

View File

@ -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>

View File

@ -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()

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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()

View File

@ -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>

View File

@ -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()

View File

@ -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()

View File

@ -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)
})
})

View File

@ -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) => {

View File

@ -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) {

View File

@ -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

View File

@ -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'

View File

@ -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)
})

View File

@ -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) => {

View File

@ -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) => {

View File

@ -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) => {

View File

@ -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 (

View File

@ -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)
})
})
},
},
})()
}

View File

@ -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
})

View File

@ -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) => {

View File

@ -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) => {

View 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)
})
})
},
},
})()
}

View File

@ -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) {

View File

@ -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
},

View File

@ -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'

View File

@ -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'

View File

@ -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) {

View File

@ -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) => {

View File

@ -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