Merge pull request #2064 from brkcvn/wizard

Wizard
This commit is contained in:
Cüneyt Şentürk
2021-05-29 20:28:08 +03:00
committed by GitHub
34 changed files with 1824 additions and 821 deletions

View File

@ -0,0 +1,131 @@
<template>
<router-view
:translations="translations"
:currencies="currencies"
:taxes="taxes"
:modules="modules.data"
:currency_codes="currency_codes"
:company="company"
></router-view>
</template>
<script>
export default {
name: "Wizard",
data: function () {
return {
page_loaded: true,
};
},
created() {
let self = this;
window
.axios({
method: "GET",
url: url + "/wizard/data",
})
.then((response) => {
let data = response.data.data;
for (let item in data) {
self[item] = data[item];
}
Object.keys(data.currency_codes).map((key) => {
return data.currency_codes[key];
});
setTimeout(
function () {
self.page_loaded = false;
}.bind(self),
800
);
});
},
data() {
return {
currencies: [],
currency_codes: [],
taxes: [],
modules: {},
company: {},
translations: {
company: {},
currencies: {},
taxes: {},
finish: {},
},
};
},
};
</script>
<style>
.document-loading {
width: 1140px;
display: flex;
align-items: center;
justify-content: center;
}
.document-loading div {
margin-top: unset;
margin-left: unset;
}
.current-tab {
background-color: #f6f9fc;
}
.current-tab-btn {
text-align: right;
padding: 0 40px;
}
.form-container {
flex-flow: row wrap;
}
.form-container .invalid-feedback {
position: absolute;
bottom: -18px;
}
.form-container .has-error {
position: relative;
margin-bottom: unset !important;
}
.form-container .has-error .form-control {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
border-right: 1px solid;
}
.el-step__icon {
-webkit-transition: unset;
transition: unset;
}
@media screen and (max-width: 991px) {
.form-container .has-error {
position: relative;
margin-bottom: 1.5rem !important;
}
.current-tab-btn {
padding: 0 15px;
}
.form-container {
flex-direction: column;
}
.form-container .form-group {
width: 100%;
}
}
</style>

View File

@ -12,6 +12,7 @@
:disabled="disabled"
>
<flat-picker slot-scope="{focus, blur}"
:name="dataName"
@on-open="focus"
@on-close="blur"
:config="dateConfig"
@ -41,6 +42,11 @@ export default {
default: '',
description: "Modal header title"
},
dataName: {
type: String,
default: '',
description: "Modal header title"
},
placeholder: {
type: String,
default: '',
@ -92,7 +98,7 @@ export default {
data() {
return {
real_model: this.model,
real_model: '',
}
},
@ -120,6 +126,12 @@ export default {
this.$emit('change', this.real_model);
}
},
watch: {
value: function(val) {
this.real_model = val;
}
}
}
</script>

View File

@ -231,6 +231,42 @@ export default {
async mounted() {
this.initDropzone();
},
watch: {
attachments: function (attachments) {
attachments.forEach((attachment) => {
if(attachment.length != undefined) {
var mockFile = {
id: attachment[0].id,
name: attachment[0].name,
size: attachment[0].size,
type: attachment[0].type,
download: attachment[0].downloadPath,
dropzone: 'edit',
};
this.dropzone.emit("addedfile", mockFile);
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, attachment[0].path);
// Make sure that there is no progress bar, etc...
this.dropzone.emit("complete", mockFile);
this.files.forEach(async (attachment) => {
if (attachment.download) {
attachment.previewElement.querySelector("[data-dz-download]").href = attachment.download;
attachment.previewElement.querySelector("[data-dz-download]").classList.remove("d-none");
}
});
if (this.preview == 'single' && attachments.length == 1) {
this.$nextTick(() => {
document.querySelector("#dropzone-" + this._uid).classList.add("dz-max-files-reached");
});
}
}
}, this);
},
},
}
</script>

View File

@ -3,7 +3,7 @@
<label :for="name" class="form-control-label">{{ text }}</label>
<div class="tab-pane tab-example-result fade show active" role="tabpanel" aria-labelledby="-component-tab">
<div class="btn-group btn-group-toggle" data-toggle="buttons" v-on:click="onClick">
<div class="btn-group btn-group-toggle radio-yes-no" data-toggle="buttons" v-on:click="onClick">
<label class="btn btn-success"
:class="[{'active': value === 1}]">
<input type="radio"
@ -70,7 +70,7 @@ export default {
},
onClick(evt) {
let val = evt.target.control.value;
this.value= val;
this.real_value = val;
this.$emit("change", val);
},

View File

@ -198,6 +198,8 @@ export default {
if (response.data.redirect) {
window.location.href = response.data.redirect;
}
this.$emit('deleted', response.data);
})
.catch(error => {
this.success = false;

View File

@ -0,0 +1,171 @@
export default {
data: function () {
return {
current_tab: undefined,
new_datas: false,
model: {
name: "",
rate: "",
select: "",
enabled: 1
},
error_field: {},
}
},
methods: {
onAddItem() {
this.new_datas = true;
this.current_tab = undefined;
this.error_field = {};
if (this.model) {
this.model.name = '';
this.model.rate = '';
this.model.select = '';
}
},
onEditItem(item, index) {
this.new_datas = false;
this.current_tab = index;
this.error_field = {};
if (this.model) {
this.model.name = item.name ? item.name : '';
this.model.rate = item.rate ? item.rate : '';
this.model.select = item.code ? item.code : '';
}
},
onCancelItem() {
this.current_tab = undefined;
},
onDataChange() {
this.new_datas = false;
this.current_tab = undefined;
this.model.name = '';
this.model.rate = '';
this.model.select = '';
this.model.enabled = 1;
},
onSuccessMessage(response) {
let type = response.data.success ? 'success' : 'error';
let timeout = 1000;
if (response.data.important) {
timeout = 0;
}
this.$notify({
message: response.data.message,
timeout: timeout,
icon: "fas fa-bell",
type,
});
this.onDataChange();
},
onDeleteItemMessage(event) {
let type = event.success ? 'success' : 'error';
let timeout = 1000;
if (event.important) {
timeout = 0;
}
this.$notify({
message: event.message,
timeout: timeout,
icon: "fas fa-bell",
type,
});
this.onDataChange();
},
onStatusControl(status_form, status_item, event) {
status_form.forEach((status) => {
if (status.id == status_item) {
status.enabled = event.target.checked;
}
});
},
onSubmitEvent(form_method, form_url, plus_data, form_list, form_id) {
const formData = new FormData(this.$refs["form"]);
const data = {};
for (let [key, val] of formData.entries()) {
Object.assign(data, {
[key]: val,
});
}
if(plus_data == 'type') {
Object.assign(data, {
['type']: 'normal',
});
}
window.axios({
method: form_method,
url: form_url,
data: data,
})
.then(response => {
if(form_list.length && form_list.length != undefined) {
if(form_method == 'POST') {
form_list.push({
"id": response.data.data.id,
"name": response.data.data.name,
"code": response.data.data.code,
"rate": response.data.data.rate,
"enabled": response.data.data.enabled != undefined ? response.data.data.enabled : 'true'
});
}
if(form_method == 'PATCH') {
form_list.forEach(item => {
if (item.id == form_id) {
item.name = response.data.data.name;
item.code = response.data.data.code;
item.rate = response.data.data.rate;
}
});
}
}
this.onSuccessMessage(response);
}, this)
.catch(error => {
this.onFailError(error);
}, this);
},
onEjetItem(event, form_list, event_id) {
form_list.forEach(function (item, index) {
if (item.id == event_id) {
form_list.splice(index, 1);
return;
}
}, this);
this.component = "";
this.onDeleteItemMessage(event);
},
onFailErrorGet(field_name) {
if(this.error_field[field_name]) {
return this.error_field[field_name][0];
}
},
onFailError(error) {
this.error_field = error.response.data.errors;
}
}
}

View File

@ -0,0 +1,243 @@
<template>
<div>
<h1 class="text-white">
{{ translations.company.title }}
</h1>
<div class="card">
<div class="card-header wizard-header p-3">
<el-steps :active="active" finish-status="success" align-center>
<el-step :title="translations.company.title"></el-step>
<el-step :title="translations.currencies.title"></el-step>
<el-step :title="translations.taxes.title"></el-step>
<el-step :title="translations.finish.title"></el-step>
</el-steps>
</div>
<form ref="form" class="w-100">
<div class="card-body">
<div class="row mb-4">
<div class="col-12 mb-4">
<base-input
:label="translations.company.api_key"
name="api_key"
data-name="api_key"
:placeholder="translations.company.api_key"
prepend-icon="fas fa-key"
v-model="company.api_key"
/>
<p class="mb-0 mt--3">
<small>
<div>
<a href="https://akaunting.com/dashboard" target="_blank"
>Click here</a
>
to get your API key.
</div>
</small>
</p>
</div>
<div class="col-6 mb-4">
<base-input
type="text"
:label="translations.company.tax_number"
name="tax_number"
data-name="tax_number"
:placeholder="translations.company.tax_number"
prepend-icon="fas fa-percent"
v-model="company.tax_number"
/>
</div>
<div class="col-6 mb-4">
<akaunting-date
:title="translations.company.financial_start"
data-name="financial_start"
:placeholder="translations.company.financial_start"
icon="fas fa-calendar"
:date-config="{
dateFormat: 'd-m',
allowInput: true,
altInput: true,
altFormat: 'j F',
}"
v-model="real_date"
></akaunting-date>
</div>
<div class="col-12 mb-4">
<base-input :label="translations.company.address">
<textarea
class="form-control"
name="address"
data-name="address"
rows="3"
:placeholder="translations.company.address"
v-model="company.address"
></textarea>
</base-input>
</div>
<div class="col-3">
<label class="form-control-label">{{
translations.company.logo
}}</label>
<akaunting-dropzone-file-upload
ref="dropzoneWizard"
preview-classes="single"
:attachments="logo"
:v-model="logo"
>
</akaunting-dropzone-file-upload>
</div>
</div>
</div>
<div class="card-footer">
<div class="row">
<div class="col-md-12 text-right">
<base-button
id="button"
type="success"
native-type="button"
@click="onEditSave()"
>{{ translations.company.save }}</base-button
>
<base-button type="white" native-type="submit" @click="next()">{{
translations.company.skip
}}</base-button>
</div>
</div>
</div>
</form>
</div>
</div>
</template>
<script>
import { Step, Steps } from "element-ui";
import AkauntingDropzoneFileUpload from "./../../components/AkauntingDropzoneFileUpload";
import AkauntingDate from "./../../components/AkauntingDate";
import WizardAction from "./../../mixins/wizardAction";
export default {
name: "Company",
mixins: [WizardAction],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
AkauntingDropzoneFileUpload,
AkauntingDate,
},
props: {
company: {
type: [Object, Array],
},
translations: {
type: [Object, Array],
},
url: {
type: String,
default: "text",
},
},
data() {
return {
active: 0,
logo: [],
real_date: "",
};
},
mounted() {
let company_data = this.company;
this.onDataWatch(company_data);
},
watch: {
company: function (company) {
this.onDataWatch(company);
},
},
methods: {
onDataWatch(company) {
if (Object.keys(company).length) {
let logo_arr = [
{
id: company.logo.id,
name: company.logo.filename + "." + company.logo.extension,
path: company.logo.path,
type: company.logo.mime_type,
size: company.logo.size,
downloadPath: false,
},
];
this.logo.push(logo_arr);
this.real_date = company.financial_start;
}
},
onEditSave() {
FormData.prototype.appendRecursive = function (data, wrapper = null) {
for (var name in data) {
if (name == "previewElement" || name == "previewTemplate") {
continue;
}
if (wrapper) {
if (
(typeof data[name] == "object" || Array.isArray(data[name])) &&
data[name] instanceof File != true &&
data[name] instanceof Blob != true
) {
this.appendRecursive(data[name], wrapper + "[" + name + "]");
} else {
this.append(wrapper + "[" + name + "]", data[name]);
}
} else {
if (
(typeof data[name] == "object" || Array.isArray(data[name])) &&
data[name] instanceof File != true &&
data[name] instanceof Blob != true
) {
this.appendRecursive(data[name], name);
} else {
this.append(name, data[name]);
}
}
}
};
const formData = new FormData(this.$refs["form"]);
let data_name = {};
for (let [key, val] of formData.entries()) {
Object.assign(data_name, {
[key]: val,
["logo"]: this.$refs.dropzoneWizard.files[1]
? this.$refs.dropzoneWizard.files[1]
: this.$refs.dropzoneWizard.files[0],
["_prefix"]: "company",
["_token"]: window.Laravel.csrfToken,
["_method"]: "POST",
});
}
formData.appendRecursive(data_name);
window
.axios({
method: "POST",
url: url + "/wizard/companies",
data: formData,
headers: {
"X-CSRF-TOKEN": window.Laravel.csrfToken,
"X-Requested-With": "XMLHttpRequest",
"Content-Type": "multipart/form-data",
},
})
.then((response) => {
this.onSuccessMessage(response);
this.$router.push("/wizard/currencies");
}, this)
.catch((error) => {
}, this);
},
next() {
if (this.active++ > 2);
this.$router.push("/wizard/currencies");
},
},
};
</script>

View File

@ -0,0 +1,422 @@
<template>
<div>
<h1 class="text-white">
{{ translations.currencies.title }}
</h1>
<div class="card">
<div class="card-header wizard-header p-3">
<el-steps :active="active" finish-status="success" align-center>
<el-step :title="translations.company.title"></el-step>
<el-step :title="translations.currencies.title"></el-step>
<el-step :title="translations.taxes.title"></el-step>
<el-step :title="translations.finish.title"></el-step>
</el-steps>
</div>
<div class="card-body">
<div class="d-flex justify-content-end mb-3">
<base-button
type="success"
native-type="button"
class="btn-sm"
@click="onAddItem()"
>{{ translations.currencies.add_new }}</base-button
>
</div>
<div class="row flex-column">
<form ref="form">
<table class="table table-flush table-hover" id="tbl-currencies">
<thead class="thead-light">
<tr class="row table-head-line">
<th class="col-xs-4 col-sm-4 col-md-3">
{{ translations.currencies.name }}
</th>
<th class="col-md-3 d-none d-md-block">
{{ translations.currencies.code }}
</th>
<th class="col-md-2 d-none d-md-block">
{{ translations.currencies.rate }}
</th>
<th class="col-xs-4 col-sm-4 col-md-2">
{{ translations.currencies.enabled }}
</th>
<th class="col-xs-4 col-sm-4 col-md-2 text-center">
{{ translations.currencies.actions }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in currencies"
:key="index"
class="row align-items-center border-top-1"
>
<td class="col-xs-4 col-sm-4 col-md-3">
<a href="javascript:void(0);"> {{ item.name }} </a>
</td>
<td class="col-md-3 d-none d-md-block">{{ item.code }}</td>
<td class="col-md-2 d-none d-md-block">{{ item.rate }}</td>
<td class="col-xs-4 col-sm-4 col-md-2">
<label class="custom-toggle d-inline-block" name="staus-1">
<input
type="checkbox"
:checked="item.enabled"
@input="onSwitchUpdate(item)"
/>
<span
class="custom-toggle-slider rounded-circle status-green"
:data-label-on="translations.currencies.yes"
:data-label-off="translations.currencies.no"
>
</span>
</label>
</td>
<td class="col-xs-4 col-sm-4 col-md-2 text-center">
<div class="dropdown">
<a
class="btn btn-neutral btn-sm text-light items-align-center py-2"
href="#"
role="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<i class="fa fa-ellipsis-h text-muted"></i>
</a>
<div
class="dropdown-menu dropdown-menu-right dropdown-menu-arrow"
>
<button
type="button"
class="dropdown-item"
@click="onEditItem(item, index)"
>
{{ translations.currencies.edit }}
</button>
<div class="dropdown-divider"></div>
<button
type="button"
class="dropdown-item"
@click="onClickDelete(item)"
>
{{ translations.currencies.delete }}
</button>
</div>
</div>
</td>
<td class="w-100 p-0 current-tab" v-if="current_tab == index">
<div class="row pt-3 pb-3">
<div
class="form-container col-12 d-flex justify-content-between align-items-start"
>
<base-input
:label="translations.currencies.name"
name="name"
data-name="name"
:placeholder="translations.currencies.name"
prepend-icon="fas fa-font"
form-classes="col-md-3"
class="required"
v-model="model.name"
:error="onFailErrorGet('name')"
/>
<base-input
:label="translations.currencies.code"
class="required"
form-classes="col-md-3"
:error="onFailErrorGet('code')"
>
<el-select
name="code"
v-model="model.select"
@change="onChangeCodeItem(model.select)"
filterable
>
<template slot="prefix">
<span
class="el-input__suffix-inner el-select-icon"
>
<i
:class="'select-icon-position el-input__icon fa fa-code'"
></i>
</span>
</template>
<el-option
v-for="option in currency_codes"
:key="option"
:label="option"
:value="option"
>
</el-option> </el-select
></base-input>
<base-input
:label="translations.currencies.rate"
name="rate"
data-name="rate"
:placeholder="translations.currencies.rate"
prepend-icon="fas fa-percentage"
form-classes="col-md-3"
class="required"
v-model="model.rate"
:error="onFailErrorGet('rate')"
/>
<div class="mt-4 col-md-3 current-tab-btn">
<base-button
type="white"
native-type="button"
@click="onCancelItem()"
>
{{ translations.currencies.cancel }}</base-button
>
<base-button
type="success"
native-type="button"
@click="onEditForm(item)"
>
{{ translations.currencies.save }}</base-button
>
</div>
</div>
</div>
</td>
</tr>
<tr v-if="new_datas">
<td class="p-0">
<div class="row pt-3 pb-3">
<div
class="form-container col-12 d-flex justify-content-between align-items-start"
>
<base-input
:label="translations.currencies.name"
name="name"
data-name="name"
:placeholder="translations.currencies.name"
prepend-icon="fas fa-font"
class="required"
v-model="model.name"
:error="onFailErrorGet('name')"
/>
<base-input
:label="translations.currencies.code"
class="required"
:error="onFailErrorGet('code')"
>
<el-select
name="code"
v-model="model.select"
required="required"
@change="onChangeCodeItem(model.select)"
filterable
>
<template slot="prefix">
<span
class="el-input__suffix-inner el-select-icon"
>
<i
:class="'select-icon-position el-input__icon fa fa-code'"
></i>
</span>
</template>
<el-option
v-for="option in currency_codes"
:key="option"
:label="option"
:value="option"
>
</el-option> </el-select
></base-input>
<base-input
:label="translations.currencies.rate"
name="rate"
data-name="rate"
:placeholder="translations.currencies.rate"
prepend-icon="fas fa-percentage"
class="required"
v-model="model.rate"
:error="onFailErrorGet('rate')"
/>
<div>
<div class="d-flex">
<akaunting-radio-group
name="enabled"
:text="translations.currencies.enabled"
:enable="translations.currencies.yes"
:disable="translations.currencies.no"
:value="model.enabled"
>
</akaunting-radio-group>
</div>
</div>
<div class="mt-4">
<base-button
type="success"
native-type="button"
@click="onSubmitForm()"
>{{ translations.currencies.save }}</base-button
>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<notifications></notifications>
<form id="form-dynamic-component" method="POST" action="#"></form>
<component
v-bind:is="component"
@deleted="onDeleteCurrency($event)"
></component>
</div>
<div class="card-footer">
<div class="row">
<div class="col-md-12 d-flex justify-content-between">
<base-button type="white" native-type="submit" @click="prev()">{{
translations.currencies.previous
}}</base-button>
<base-button type="white" native-type="submit" @click="next()">{{
translations.currencies.next
}}</base-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Step, Steps, Select, Option } from "element-ui";
import AkauntingRadioGroup from "./../../components/forms/AkauntingRadioGroup";
import BulkAction from "./../../plugins/bulk-action";
import MixinsGlobal from "./../../mixins/global";
import WizardAction from "./../../mixins/wizardAction";
export default {
name: "Currencies",
mixins: [MixinsGlobal, WizardAction],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
[Select.name]: Select,
[Option.name]: Option,
AkauntingRadioGroup,
},
props: {
currencies: {
type: [Object, Array],
},
currency_codes: {
type: [Object, Array],
},
translations: {
type: [Object, Array],
},
},
data() {
return {
active: 1,
bulk_action: new BulkAction(url + "/settings/currencies"),
};
},
methods: {
onSwitchUpdate(item) {
this.onStatus(item.id, event);
this.onStatusControl(this.currencies, item.id, event);
},
onClickDelete(item) {
this.confirmDelete(
`${
new URL(url).protocol +
"//" +
location.host +
location.pathname +
"/" +
item.id
}`,
this.translations.currencies.title,
`Confirm Delete <strong>${item.name}</strong> ${this.translations.currencies.title}?`,
this.translations.currencies.cancel,
this.translations.currencies.delete
);
},
onDeleteCurrency(event) {
this.onEjetItem(event, this.currencies, event.currency_id);
},
onChangeCodeItem(code) {
const formData = new FormData(this.$refs["form"]);
const data = {
rate: "",
precision: "",
symbol: "",
symbol_first: "",
decimal_mark: "",
thousands_separator: "",
};
for (let [key, val] of formData.entries()) {
Object.assign(data, {
[key]: val,
});
}
window
.axios({
method: "GET",
url: url + "/settings/currencies/config",
params: {
code: code,
},
})
.then((response) => {
data.rate = response.data.rate;
data.precision = response.data.precision;
data.symbol = response.data.symbol;
data.symbol_first = response.data.symbol_first;
data.decimal_mark = response.data.decimal_mark;
data.thousands_separator = response.data.thousands_separator;
this.model.rate = response.data.rate;
}, this);
},
onEditForm(item) {
this.onSubmitEvent(
"PATCH",
url + "/wizard/currencies/" + item.id,
"",
this.currencies,
item.id
);
},
onSubmitForm() {
this.onSubmitEvent(
"POST",
url + "/wizard/currencies",
"",
this.currencies
);
},
prev() {
if (this.active-- > 2);
history.back()
this.$router.push("/wizard/companies");
},
next() {
if (this.active++ > 2);
this.$router.push("/wizard/taxes");
},
},
};
</script>

View File

@ -0,0 +1,143 @@
<template>
<div v-if="is_loaded">
<h1 class="text-white">{{ translations.finish.title }}</h1>
<div class="card">
<div class="card-header wizard-header p-3">
<el-steps :active="active" finish-status="success" align-center>
<el-step :title="translations.company.title"></el-step>
<el-step :title="translations.currencies.title"></el-step>
<el-step :title="translations.taxes.title"></el-step>
<el-step :title="translations.finish.title"></el-step>
</el-steps>
</div>
<div class="card-body bg-default">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 col-xl-12">
<div class="content-header">
<h3 class="text-white">
{{ translations.finish.recommended_apps }}
</h3>
</div>
<div class="row">
<div
v-for="(item, index) in modules"
:key="index"
class="col-md-3"
>
<div class="card">
<div class="card-header py-2">
<h4 class="ml--3 mb-0 float-left">
<a :href="item.slug">{{ item.name }}</a>
</h4>
</div>
<a :href="route_url + '/' + item.slug"
><img
v-for="(file, indis) in item.files"
:key="indis"
v-if="
file.media_type == 'image' &&
file.pivot.zone == 'thumbnail'
"
:src="file.path_string"
:alt="item.name"
class="card-img-top border-radius-none"
/></a>
<div class="card-footer py-2">
<div class="float-left ml--3 mt--1">
<i
v-for="(stars, indis) in item.vote"
:key="indis"
class="fa fa-star text-xs text-yellow"
></i>
<small class="text-xs"> {{ item.total_review }} </small>
</div>
<div class="float-right mr--3">
<small
><strong> {{ item.price }} </strong></small
>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12"><ul></ul></div>
</div>
</div>
</div>
<div class="card-footer">
<div class="row">
<div class="col-md-12 d-flex justify-content-between">
<base-button type="white" native-type="submit" @click="prev()">{{
translations.finish.previous
}}</base-button>
<base-button
type="success"
native-type="submit"
@click="finish()"
>{{ translations.finish.go_to_dashboard }}</base-button
>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Step, Steps } from "element-ui";
export default {
name: "Finish",
components: {
[Step.name]: Step,
[Steps.name]: Steps,
},
created() {
window
.axios({
method: "PATCH",
url: url + "/wizard/finish",
})
.then((response) => {
if (response.status == "200") {
this.is_loaded = true;
}
})
.catch((error) => {
this.$notify({
message: this.translations.finish.error_message,
timeout: 1000,
icon: "fas fa-bell",
type: 0
});
this.prev();
});
},
props: {
modules: {
type: [Object, Array],
},
translations: {
type: [Object, Array],
}
},
data() {
return {
active: 3,
route_url: url,
is_loaded: false
};
},
methods: {
prev() {
if (this.active-- > 2);
this.$router.push("/wizard/taxes");
},
finish() {
window.location.href = url;
},
},
};
</script>

View File

@ -0,0 +1,315 @@
<template>
<div>
<h1 class="text-white">{{ translations.taxes.title }}</h1>
<div class="card">
<div class="card-header wizard-header p-3">
<el-steps :active="active" finish-status="success" align-center>
<el-step :title="translations.company.title"></el-step>
<el-step :title="translations.currencies.title"></el-step>
<el-step :title="translations.taxes.title"></el-step>
<el-step :title="translations.finish.title"></el-step>
</el-steps>
</div>
<div class="card-body">
<div class="d-flex justify-content-end mb-3">
<base-button
type="success"
native-type="button"
class="btn-sm"
@click="onAddItem()"
>{{ translations.taxes.add_new }}</base-button
>
</div>
<div class="row flex-column">
<form ref="form">
<table class="table table-flush table-hover" id="tbl-taxes">
<thead class="thead-light">
<tr class="row table-head-line">
<th class="col-xs-4 col-sm-4 col-md-3">
{{ translations.taxes.name }}
</th>
<th class="col-md-3 d-none d-md-block">
{{ translations.taxes.rate }}
</th>
<th class="col-xs-4 col-sm-4 col-md-3">
{{ translations.taxes.enabled }}
</th>
<th class="col-xs-4 col-sm-4 col-md-3 text-center">
{{ translations.taxes.actions }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in taxes"
:key="index"
class="row align-items-center border-top-1"
>
<td class="col-xs-4 col-sm-4 col-md-3 tax-name">
<a href="javascript:void(0);"> {{ item.name }} </a>
</td>
<td class="col-md-3 d-none d-md-block">{{ item.rate }}</td>
<td class="col-xs-4 col-sm-4 col-md-3">
<label class="custom-toggle d-inline-block" name="staus-1">
<input
type="checkbox"
:checked="item.enabled"
@input="onSwitchUpdate(item)"
/>
<span
class="custom-toggle-slider rounded-circle status-green"
:data-label-on="translations.taxes.yes"
:data-label-off="translations.taxes.no"
>
</span>
</label>
</td>
<td class="col-xs-4 col-sm-4 col-md-3 text-center">
<div class="dropdown">
<a
class="btn btn-neutral btn-sm text-light items-align-center py-2"
href="#"
role="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<i class="fa fa-ellipsis-h text-muted"></i>
</a>
<div
class="dropdown-menu dropdown-menu-right dropdown-menu-arrow"
>
<button
type="button"
class="dropdown-item"
@click="onEditItem(item, index)"
>
{{ translations.taxes.edit }}
</button>
<div class="dropdown-divider"></div>
<button
type="button"
class="dropdown-item"
@click="onClickDelete(item)"
>
{{ translations.taxes.delete }}
</button>
</div>
</div>
</td>
<td class="w-100 p-0 current-tab" v-if="current_tab == index">
<div class="row pt-3 pb-3">
<div
class="form-container col-12 d-flex justify-content-between align-items-start"
>
<base-input
:label="translations.taxes.name"
name="name"
data-name="name"
:placeholder="translations.taxes.name"
prepend-icon="fas fa-font"
form-classes="col-md-4"
class="required"
v-model="model.name"
:error="onFailErrorGet('name')"
/>
<base-input
:label="translations.taxes.rate"
name="rate"
data-name="rate"
:placeholder="translations.taxes.rate"
prepend-icon="fas fa-percentage"
form-classes="col-md-4"
class="required"
v-model="model.rate"
:error="onFailErrorGet('rate')"
/>
<div class="mt-4 col-md-4 current-tab-btn">
<base-button
type="white"
native-type="button"
@click="onCancelItem()"
>
{{ translations.taxes.cancel }}</base-button
>
<base-button
type="success"
native-type="button"
@click="onEditForm(item)"
>{{ translations.taxes.save }}</base-button
>
</div>
</div>
</div>
</td>
</tr>
<tr v-if="new_datas">
<td class="p-0">
<div class="row pt-3 pb-3">
<div
class="form-container col-12 d-flex justify-content-between align-items-start"
>
<base-input
:label="translations.taxes.name"
name="name"
data-name="name"
:placeholder="translations.taxes.name"
prepend-icon="fas fa-font"
class="required"
v-model="model.name"
:error="onFailErrorGet('name')"
/>
<base-input
:label="translations.taxes.rate"
name="rate"
data-name="rate"
:placeholder="translations.taxes.rate"
prepend-icon="fas fa-percentage"
class="required"
v-model="model.rate"
:error="onFailErrorGet('rate')"
/>
<div>
<div class="d-flex">
<akaunting-radio-group
name="enabled"
:text="translations.taxes.enabled"
:enable="translations.taxes.yes"
:disable="translations.taxes.no"
:value="model.enabled"
>
</akaunting-radio-group>
</div>
</div>
<div class="mt-4">
<base-button
type="success"
native-type="button"
@click="onSubmitForm()"
>{{ translations.taxes.save }}</base-button
>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<notifications></notifications>
<form id="form-dynamic-component" method="POST" action="#"></form>
<component
v-bind:is="component"
@deleted="onDeleteCurrency($event)"
></component>
</div>
<div class="card-footer">
<div class="row">
<div class="col-md-12 d-flex justify-content-between">
<base-button type="white" native-type="submit" @click="prev()">{{
translations.taxes.previous
}}</base-button>
<base-button type="white" native-type="submit" @click="next()">{{
translations.taxes.next
}}</base-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Step, Steps } from "element-ui";
import AkauntingRadioGroup from "./../../components/forms/AkauntingRadioGroup";
import BulkAction from "./../../plugins/bulk-action";
import MixinsGlobal from "./../../mixins/global";
import WizardAction from "./../../mixins/wizardAction";
export default {
name: "Taxes",
mixins: [MixinsGlobal, WizardAction],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
AkauntingRadioGroup,
},
props: {
taxes: {
type: [Object, Array],
},
translations: {
type: [Object, Array],
},
},
data() {
return {
active: 2,
bulk_action: new BulkAction(url + "/settings/taxes"),
};
},
methods: {
onSwitchUpdate(item) {
this.onStatus(item.id, event);
this.onStatusControl(this.taxes, item.id, event);
},
onClickDelete(item) {
this.confirmDelete(
`${
new URL(url).protocol +
"//" +
location.host +
location.pathname +
"/" +
item.id
}`,
this.translations.taxes.title,
`${
this.translations.currencies.title +
"&nbsp;" +
this.translations.currencies.delete
} <strong>${item.name}</strong>?`,
this.translations.taxes.cancel,
this.translations.taxes.delete
);
},
onDeleteCurrency(event) {
this.onEjetItem(event, this.taxes, event.tax_id);
},
onEditForm(item) {
this.onSubmitEvent(
"PATCH",
url + "/wizard/taxes/" + item.id,
"type",
this.taxes,
item.id
);
},
onSubmitForm() {
this.onSubmitEvent("POST", url + "/wizard/taxes", "type", this.taxes);
},
prev() {
if (this.active-- > 2);
this.$router.push("/wizard/currencies");
},
next() {
if (this.active++ > 2);
this.$router.push("/wizard/finish");
},
},
};
</script>
<style scoped>
.current-tab-btn {
padding: 0 80px;
}
</style>

View File

@ -1,44 +0,0 @@
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./../../bootstrap');
import Vue from 'vue';
import DashboardPlugin from './../../plugins/dashboard-plugin';
import Global from './../../mixins/global';
import Form from './../../plugins/form';
import {Step, Steps} from 'element-ui';
// plugin setup
Vue.use(DashboardPlugin, Step, Steps);
const app = new Vue({
el: '#app',
mixins: [
Global
],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
},
data: function () {
return {
form: new Form('company'),
active: 0
}
},
methods: {
}
});

View File

@ -1,114 +0,0 @@
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('../../bootstrap');
import Vue from 'vue';
import DashboardPlugin from './../../plugins/dashboard-plugin';
import Global from '../../mixins/global';
import Form from '../../plugins/form';
import BulkAction from './../../plugins/bulk-action';
import {Step, Steps} from 'element-ui';
// plugin setup
Vue.use(DashboardPlugin, Step, Steps);
const app = new Vue({
el: '#app',
mixins: [
Global
],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
},
data: function () {
return {
form: new Form('currency'),
active: 1,
bulk_action: new BulkAction(url + '/settings/currencies'),
show: false,
currency: {
name: '',
code: '',
rate: '1',
enabled: 1
},
submit_function: '',
}
},
methods: {
onAddCurrency() {
this.submit_function = 'onStoreCurrency';
this.form.method = 'post';
this.form.action = url + '/wizard/currencies';
this.form.name = '';
this.form.code = '';
this.form.rate = '';
this.form.enabled = 1;
this.form.precision = '';
this.form.symbol = '';
this.form.symbol_first = '';
this.form.decimal_mark = '';
this.form.thousands_separator = '';
this.show = true;
},
onEditCurrency(currency_id) {
this.submit_function = 'onUpdateCurrency';
this.form.method = 'patch';
this.form.action = url + '/wizard/currencies/' + currency_id;
currencies.forEach(currency => {
if (currency.id == currency_id) {
this.form.name = currency.name;
this.form.code = currency.code;
this.form.rate = currency.rate;
this.form.enabled = currency.enabled;
this.form.precision = currency.precision;
this.form.symbol = currency.symbol;
this.form.symbol_first = currency.symbol_first;
this.form.decimal_mark = currency.decimal_mark;
this.form.thousands_separator = currency.thousands_separator;
}
});
this.show = true;
},
onChangeCode(code) {
axios.get(url + '/settings/currencies/config', {
params: {
code: code
}
})
.then(response => {
this.form.rate = response.data.rate;
this.form.precision = response.data.precision;
this.form.symbol = response.data.symbol;
this.form.symbol_first = response.data.symbol_first;
this.form.decimal_mark = response.data.decimal_mark;
this.form.thousands_separator = response.data.thousands_separator;
})
.catch(error => {
});
},
onSubmit() {
this.form.oldSubmit();
},
}
});

View File

@ -1,41 +0,0 @@
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./../../bootstrap');
import Vue from 'vue';
import DashboardPlugin from './../../plugins/dashboard-plugin';
import Global from './../../mixins/global';
import {Step, Steps} from 'element-ui';
// plugin setup
Vue.use(DashboardPlugin, Step, Steps);
const app = new Vue({
el: '#app',
mixins: [
Global
],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
},
data: function () {
return {
active: 3,
}
},
methods: {
}
});

View File

@ -1,86 +0,0 @@
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('../../bootstrap');
import Vue from 'vue';
import DashboardPlugin from './../../plugins/dashboard-plugin';
import Global from '../../mixins/global';
import Form from '../../plugins/form';
import BulkAction from './../../plugins/bulk-action';
import {Step, Steps} from 'element-ui';
// plugin setup
Vue.use(DashboardPlugin, Step, Steps);
const app = new Vue({
el: '#app',
mixins: [
Global
],
components: {
[Step.name]: Step,
[Steps.name]: Steps,
},
data: function () {
return {
form: new Form('tax'),
active: 2,
bulk_action: new BulkAction(url + '/settings/taxes'),
show: false,
tax: {
name: '',
code: '',
type: 'normal',
enabled: 1
},
submit_function: ''
}
},
methods: {
onAddTax() {
this.submit_function = 'onStoreTax';
this.form.method = 'post';
this.form.action = url + '/wizard/taxes';
this.form.name = '';
this.form.rate = '';
this.form.type = 'normal';
this.form.enabled = 1;
this.show = true;
},
onEditTax(tax_id) {
this.submit_function = 'onUpdateTax';
this.form.method = 'patch';
this.form.action = url + '/wizard/taxes/' + tax_id;
taxes.forEach(tax => {
if (tax.id == tax_id) {
this.form.name = tax.name;
this.form.rate = tax.rate;
this.form.type = tax.type;
this.form.enabled = tax.enabled;
}
});
this.show = true;
},
onSubmit() {
this.form.oldSubmit();
},
}
});

67
resources/assets/js/wizard.js vendored Normal file
View File

@ -0,0 +1,67 @@
require('./bootstrap');
import Vue from 'vue';
import VueRouter from 'vue-router';
import DashboardPlugin from './plugins/dashboard-plugin';
Vue.use(DashboardPlugin);
Vue.use(VueRouter);
import Wizard from './Wizard.vue';
import Company from './views/wizard/Company.vue';
import Currencies from './views/wizard/Currencies.vue';
import Taxes from './views/wizard/Taxes.vue';
import Finish from './views/wizard/Finish.vue';
var global_path = new URL(url).protocol + '//' + window.location.host;
var base_path = url.replace(global_path, '');
const router = new VueRouter({
mode: 'history',
base: base_path,
routes: [
{
path: '/wizard',
name: 'Wizard',
component: Company
},
{
path: '/wizard/companies',
name: 'Company',
component: Company
},
{
path: '/wizard/currencies',
name: 'Currencies',
component: Currencies
},
{
path: '/wizard/taxes',
name: 'Taxes',
component: Taxes
},
{
path: '/wizard/finish',
name: 'Finish',
component: Finish
}
],
linkActiveClass: 'active',
scrollBehavior: (to, from ,savedPosition) => {
if (savedPosition) {
return savedPosition;
}
if (to.hash) {
return { selector: to.hash };
}
return { x: 0, y: 0 };
}
});
new Vue({
el : '#app',
router,
render: h => h(Wizard),
});