Skip to content
This repository has been archived by the owner on Dec 21, 2021. It is now read-only.

Commit

Permalink
Merge in additional report screens
Browse files Browse the repository at this point in the history
commit 95e6e56
Author: Alec Ritson <[email protected]>
Date:   Fri Oct 18 16:33:27 2019 +0100

    Compile

commit 792e0ad
Author: Alec Ritson <[email protected]>
Date:   Fri Oct 18 16:31:50 2019 +0100

    Fix page titles

commit 5cb44e4
Author: Alec Ritson <[email protected]>
Date:   Fri Oct 18 16:29:28 2019 +0100

    Register report components

commit 0c5f82a
Author: Alec Ritson <[email protected]>
Date:   Fri Oct 18 16:29:11 2019 +0100

    Add shipping and attribute reports
  • Loading branch information
alecritson committed Oct 28, 2019
1 parent b4799e3 commit ac0da8d
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 3 deletions.
164 changes: 164 additions & 0 deletions resources/assets/js/components/reports/products/ProductAttributes.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<template>
<div>
<div class="tab-content section block">
<div role="tabpanel" class="tab-pane active">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>Attribute</label>
<select class="form-control" v-model="attribute">
<option value>Select an attribute</option>
<option v-for="attribute in attributes" :value="attribute" :key="attribute.id">{{ attribute.name.en }}</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>Value</label>
<template v-if="loadingAttributeValues">
<div>
<i class="fa fa-sync fa-spin"></i> Fetching values
</div>
</template>
<template v-else>
<select class="form-control" v-model="attributeValue">
<option value>Select an attribute Value</option>
<option v-for="(row, index) in attributeValues" :value="row.value" :key="index">{{ row.value ? row.value : 'EMPTY' }} ({{ row.count }})</option>
</select>
<p class="text-danger" v-if="tooManyUniqueValues">
There are too many unique values, showing a small subset.
</p>
</template>
</div>
</div>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Product</th>
<th>SKU</th>
</tr>
</thead>
<tfoot v-if="searching">
<tr>
<td colspan="4">
<i class="fa fa-sync fa-spin"></i> Loading
</td>
</tr>
</tfoot>
<tbody>
<tr v-for="product in products" :key="product.id">
<td><a :href="route('hub.products.edit', product.sku)">{{ product.name }}</a></td>
<td>{{ product.sku }}</td>
</tr>
</tbody>
</table>
<candy-table-paginate v-if="products.length" :total="totalPages" :current="page" @change="changePage"></candy-table-paginate>
</div>
</div>
</div>
</template>

<script>
import UrlHelper from '../../../classes/UrlHelpers';
export default {
data() {
return {
products: [],
page: 1,
urlParams: UrlHelper.params(),
totalPages: 1,
searching: false,
tooManyUniqueValues: false,
attribute: '',
attributes: [],
attributeValues: [],
attributeValue: '',
loadingAttributeValues: false,
}
},
mounted() {
this.loadAttributes(1);
// if (this.attribute) {}
},
watch: {
attribute(val) {
if (val) {
UrlHelper.setParam('attribute', val.handle);
this.loadAttributeValues(1);
} else {
UrlHelper.setParam('attribute', val);
}
},
attributeValue(val) {
UrlHelper.setParam('attribute_value', val);
if (val) {
this.search();
}
}
},
methods: {
loadAttributes(page) {
apiRequest.send('get', '/attributes', [], {
page: page,
})
.then(response => {
this.attributes = _.sortBy([...this.attributes, ...response.data], 'handle');
const attribute = this.urlParams.get('attribute') ? this.urlParams.get('attribute') : '';
this.attribute = _.find(this.attributes, (att) => {
return att.handle == attribute;
});
if (page < response.meta.pagination.total_pages) {
this.loadAttributes(page + 1);
}
});
},
loadAttributeValues(page) {
this.tooManyUniqueValues = false;
this.attributeValues = [];
this.loadingAttributeValues = true;
apiRequest.send('get', '/reports/attributes', [], {
attribute: this.attribute.handle,
})
.then(response => {
this.attributeValues = _.sortBy([...this.attributeValues, ...response.data], 'handle');
this.attributeValue = this.urlParams.get('attribute_value') ? this.urlParams.get('attribute_value') : '';
// Only get the first 5 pages to avoid an crazy api spam
if (response.last_page > 5) {
this.tooManyUniqueValues = true;
}
if ((page <= 5) && (page < response.last_page)) {
this.loadAttributeValues(page + 1);
} else {
this.loadingAttributeValues = false;
}
});
},
changePage(page) {
this.page = page;
this.search();
},
search() {
this.searching = true;
this.products = [];
apiRequest.send('get', '/reports/products/attributes', [], {
attribute: this.attribute.handle,
attribute_value: this.attributeValue,
page: this.page,
})
.then(response => {
this.searching = false;
this.products = response.data;
this.page = response.current_page;
this.totalPages = response.last_page;
});
}
}
}
</script>

<style scoped>
</style>
181 changes: 181 additions & 0 deletions resources/assets/js/components/reports/shipping/ShippingMethods.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<template>
<div>

<div class="panel">
<div class="panel-heading" v-if="showControls">
<div class="row">
<div class="col-md-3">
<div class="form-group">
<label>Date Range</label>
<candy-daterange-picker @update="update" :from="fromDate.format('YYYY-MM-DD')" :to="toDate.format('YYYY-MM-DD')" />
</div>
</div>
<div class="col-md-1">
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label>Frequency</label>
<select class="form-control" v-model="viewMode" @change="refresh">
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</select>
</div>
</div>
<div class="col-md-1">
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label>Graph Type</label>
<select class="form-control" v-model="style" @change="refresh">
<option value="line">Line</option>
<option value="bar">Bar</option>
</select>
</div>
</div>
</div>
</div>
<div class="panel-body">

<div v-show="loading">
<span><i class="fa fa-sync fa-spin"></i></span> Loading Report
</div>
<canvas ref="graph" v-show="!loading"/>
</div>
</div>
</div>
</template>

<script>
export default {
props: {
to: {
type: String
},
from: {
type: String,
},
mode: {
type: String,
default: 'weekly',
},
showControls: {
type: Boolean,
default: true,
}
},
data() {
return {
chart: null,
loading: true,
fromDate: this.from,
toDate: this.to,
viewMode: this.mode,
style: 'line',
}
},
created() {
if (!this.fromDate || !this.toDate) {
this.fromDate = moment().subtract(1, 'months');
this.toDate = moment().add(1, 'day');
} else {
this.fromDate = moment(this.from).subtract(1, 'months');
this.toDate = moment(this.to);
}
this.refresh();
},
methods: {
update(event) {
this.fromDate = event.start;
this.toDate = event.end;
this.refresh();
},
refresh() {
this.loading = true;
// Get the report we want.
apiRequest.send('GET', '/reports/shipping', {}, {
from: this.fromDate.format('YYYY-MM-DD'),
to: this.toDate.format('YYYY-MM-DD'),
mode: this.viewMode,
}).then(response => {
console.log(response);
const ctx = this.$refs.graph.getContext("2d");
this.loading = false;
if (this.chart) {
this.chart.destroy();
}
this.chart = new Chart(ctx, {
type: this.style,
data: response,
options: {
responsive: true,
}
});
// type: this.style,
// data: response,
// options: {
// responsive: true,
// tooltips: {
// mode: 'index',
// intersect: false,
// callbacks: {
// label: function(tooltipItem, data) {
// var label = tooltipItem.yLabel;
// if (tooltipItem.datasetIndex == 1) {
// label = '£' + tooltipItem.yLabel.money();
// }
// return data.datasets[tooltipItem.datasetIndex].label + ': ' + label;
// }
// }
// },
// hover: {
// mode: 'nearest',
// intersect: true
// },
// scales: {
// xAxes: [{
// display: true,
// scaleLabel: {
// display: true,
// labelString: 'Week'
// }
// }],
// yAxes: [
// {
// id: 'A',
// position:'left',
// ticks: {
// beginAtZero: true
// },
// scaleLabel: {
// display: true,
// labelString: '# Orders'
// }
// },
// {
// id: 'B',
// position:'right',
// ticks: {
// beginAtZero: true,
// callback: function(value, index, values) {
// return '£' + value.money();
// }
// },
// scaleLabel: {
// display: true,
// labelString: 'Total Value'
// }
// }
// ]
// }
// }
// });
}).catch(errors => {
});
}
}
}
</script>

<style scoped>
</style>
2 changes: 2 additions & 0 deletions resources/assets/js/hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ _.each(CandyHub.plugins, plugin => {

// Gradually move top level components into here, so we can use local registration per component.
Vue.component('candy-sales-report', require('./components/reports/SalesReport.vue'));
Vue.component('candy-shipping-method-report', require('./components/reports/shipping/ShippingMethods.vue'));
Vue.component('candy-product-attributes-report', require('./components/reports/products/ProductAttributes.vue'));
Vue.component('candy-dashboard-metrics', require('./components/reports/Metrics.vue'));
Vue.component('candy-orders-report', require('./components/reports/OrdersReport.vue'));
Vue.component('candy-attributes-table', require('./components/catalogue-manager/attributes/Table.vue'));
Expand Down
2 changes: 1 addition & 1 deletion resources/build/js/candyhub.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion resources/build/js/hub.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/build/js/setup.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions resources/lang/en/titles.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@
'discounts' => 'Discounts',
'customers' => 'Customers',
'sales-report' => 'Sales Report',
'product-attributes-report' => 'Product Attributes',
'shipping-report' => 'Shipping Report',
];
16 changes: 16 additions & 0 deletions resources/views/reports/products/attributes.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@extends('hub::layout', [
'title' => 'Product Attribute Report',
])

@section('side_menu')
@include('hub::reports.partials.side-menu')
@endsection

@section('header_title')
<small>Reports</small>
<h1>Product Attribute Report</h1>
@endsection

@section('content')
<candy-product-attributes-report />
@endsection
Loading

0 comments on commit ac0da8d

Please sign in to comment.