Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanmcclean committed Dec 4, 2024
1 parent 96e0fbb commit b5bbf28
Show file tree
Hide file tree
Showing 38 changed files with 2,357 additions and 95 deletions.
27 changes: 17 additions & 10 deletions config/simple-commerce.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
<?php

use DuncanMcClean\SimpleCommerce\Cart\Calculator\ApplyCouponDiscounts;
use DuncanMcClean\SimpleCommerce\Cart\Calculator\ApplyShipping;
use DuncanMcClean\SimpleCommerce\Cart\Calculator\CalculateGrandTotal;
use DuncanMcClean\SimpleCommerce\Cart\Calculator\CalculateLineItems;
use DuncanMcClean\SimpleCommerce\Cart\Calculator\ResetTotals;
use DuncanMcClean\SimpleCommerce\Cart\Calculator;

return [

Expand All @@ -31,14 +27,25 @@
'merge_on_login' => true,

'calculator_pipeline' => [
ResetTotals::class,
CalculateLineItems::class,
ApplyCouponDiscounts::class,
ApplyShipping::class,
CalculateGrandTotal::class,
Calculator\ResetTotals::class,
Calculator\CalculateLineItems::class,
Calculator\ApplyCouponDiscounts::class,
Calculator\ApplyShipping::class,
Calculator\CalculateGrandTotal::class,
],
],

'taxes' => [
// Enable this when product prices are entered inclusive of tax.
// When calculating taxes, the tax will be deducted from the product price, then added back on at the end.
'price_includes_tax' => true,

// Determines how tax is calculated on shipping costs. Options:
// - highest_tax_rate: Charge the highest tax rate from the products in the cart.
// - tax_class: When enabled, a new tax class will be created for shipping, allowing you to set a specific tax rate for shipping.
'shipping_tax_behaviour' => 'none',
],

'orders' => [
'directory' => base_path('content/orders'),
],
Expand Down
140 changes: 116 additions & 24 deletions resources/js/components/fieldtypes/StateFieldtype.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,70 @@
<template>
<div>
<!-- TODO: Figure out how to make the label the name of the region, instead of the code. -->
<div class="flex">
<v-select
ref="input"
:input-id="fieldId"
class="flex-1"
append-to-body
searchable
close-on-select
clearable
:calculate-position="positionOptions"
:name="name"
:clearable="true"
:disabled="config.disabled || isReadOnly"
:disabled="config.disabled || isReadOnly || (multiple && limitReached)"
:options="options"
:searchable="true"
:multiple="false"
:reset-on-options-change="resetOnOptionsChange"
:close-on-select="true"
:value="value"
:multiple="multiple"
:value="selectedOptions"
:get-option-key="(option) => option.value"
:loading="loading"
@input="vueSelectUpdated"
@focus="$emit('focus')"
@search:focus="$emit('focus')"
@search:blur="$emit('blur')">
<template #selected-option-container v-if="multiple"><i class="hidden"></i></template>
<template #search="{ events, attributes }" v-if="multiple">
<input
:placeholder="__(config.placeholder)"
class="vs__search"
type="search"
v-on="events"
v-bind="attributes"
>
</template>
<template #option="{ label }">
<div v-html="label" />
</template>
<template #selected-option="{ label }">
<div v-html="label" />
</template>
<template #no-options>
<div class="text-sm text-gray-700 rtl:text-right ltr:text-left py-2 px-4" v-text="__('No options to choose from.')" />
</template>
<template #footer="{ deselect }" v-if="multiple">
<sortable-list
item-class="sortable-item"
handle-class="sortable-item"
:value="value"
:distance="5"
:mirror="false"
@input="update"
>
<div class="vs__selected-options-outside flex flex-wrap">
<span v-for="option in selectedOptions" :key="option.value" class="vs__selected mt-2 sortable-item" :class="{'invalid': option.invalid}">
<div v-html="option.label" />
<button v-if="!readOnly" @click="deselect(option)" type="button" :aria-label="__('Deselect option')" class="vs__deselect">
<span>×</span>
</button>
<button v-else type="button" class="vs__deselect">
<span class="text-gray-500">×</span>
</button>
</span>
</div>
</sortable-list>
</template>
</v-select>
<div class="text-xs rtl:mr-2 ltr:ml-2 mt-3" :class="limitIndicatorColor" v-if="config.max_items > 1">
<span v-text="currentLength"></span>/<span v-text="config.max_items"></span>
</div>
</div>
</template>

Expand Down Expand Up @@ -57,16 +97,72 @@ export default {
return utf8btoa(JSON.stringify(this.config));
},
resetOnOptionsChange() {
// Reset the value if the value doesn't exist in the new set of options.
return (options, old, val) => {
let opts = options.map(o => o.value);
return !val.some(v => opts.includes(v.value));
};
multiple() {
return this.config.max_items !== 1;
},
selectedOptions() {
let selections = this.value || [];
if (typeof selections === 'string' || typeof selections === 'number') {
selections = [selections];
}
return selections.map(value => {
let option = this.options.find(option => option.value === value);
if (! option) return {value, label: value};
return {value: option.value, label: option.label, invalid: false};
});
},
limitReached() {
if (!this.config.max_items) return false;
return this.currentLength >= this.config.max_items;
},
limitExceeded() {
if (!this.config.max_items) return false;
return this.currentLength > this.config.max_items;
},
currentLength() {
if (this.value) {
return (typeof this.value == 'string') ? 1 : this.value.length;
}
return 0;
},
limitIndicatorColor() {
if (this.limitExceeded) {
return 'text-red-500';
} else if (this.limitReached) {
return 'text-green-600';
}
return 'text-gray';
},
},
methods: {
vueSelectUpdated(value) {
if (this.multiple) {
this.update(value.map(v => v.value));
// value.forEach((option) => this.states.push(option));
} else {
if (value) {
this.update(value.value)
// this.states.push(value)
} else {
this.update(null);
}
}
},
request(params = {}) {
params = {
config: this.configParameter,
Expand All @@ -78,20 +174,16 @@ export default {
return Promise.resolve(response);
});
},
vueSelectUpdated(value) {
if (value) {
this.update(value.value)
} else {
this.update(null);
}
},
},
watch: {
country (country) {
this.loading = true;
this.update(null);
if (this.config.max_items === 1) {
this.update(null);
}
this.request({ country }).then(response => this.loading = false);
},
},
Expand Down
65 changes: 65 additions & 0 deletions resources/js/components/tax-classes/CreateForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<div class="max-w-lg mt-4 mx-auto">

<div class="rounded p-6 lg:px-20 lg:py-10 shadow bg-white dark:bg-dark-600 dark:shadow-dark">
<header class="text-center mb-16">
<h1 class="mb-6">{{ __('Create Tax Class') }}</h1>
<!-- <p class="text-gray" v-text="__('messages.collection_configure_intro')" />-->
</header>
<div class="mb-10">
<label class="font-bold text-base mb-1" for="name">{{ __('Name') }}</label>
<input type="text" v-model="name" class="input-text" autofocus tabindex="1">
<!-- <div class="text-2xs text-gray-600 mt-2 flex items-center">-->
<!-- {{ __('messages.collection_configure_title_instructions') }}-->
<!-- </div>-->
</div>
</div>

<div class="flex justify-center mt-8">
<button tabindex="4" class="btn-primary mx-auto btn-lg" :disabled="! canSubmit" @click="submit">
{{ __('Create Tax Class')}}
</button>
</div>
</div>
</template>

<script>
export default {
props: {
route: {
type: String
}
},
data() {
return {
name: null,
}
},
computed: {
canSubmit() {
return Boolean(this.name);
},
},
methods: {
submit() {
this.$axios.post(this.route, {name: this.name}).then(response => {
window.location = response.data.redirect;
}).catch(error => {
this.$toast.error(error.response.data.message);
});
}
},
mounted() {
this.$keys.bindGlobal(['return'], e => {
if (this.canSubmit) {
this.submit();
}
});
}
}
</script>
49 changes: 49 additions & 0 deletions resources/js/components/tax-classes/Listing.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<data-list :rows="rows" :columns="columns">
<div class="card p-0" slot-scope="{ }">
<data-list-table>
<template slot="cell-name" slot-scope="{ row: taxClass, index }">
<a :href="taxClass.edit_url">{{ __(taxClass.name) }}</a>
</template>
<template slot="actions" slot-scope="{ row: taxClass, index }">
<dropdown-list>
<dropdown-item :text="__('Edit')" :redirect="taxClass.edit_url" />
<dropdown-item
:text="__('Delete')"
class="warning"
@click="$refs[`deleter_${taxClass.id}`].confirm()"
>
<resource-deleter
:ref="`deleter_${taxClass.id}`"
:resource="taxClass"
@deleted="removeRow(taxClass)">
</resource-deleter>
</dropdown-item>
</dropdown-list>
</template>
</data-list-table>
</div>
</data-list>
</template>

<script>
import Listing from '../../../../vendor/statamic/cms/resources/js/components/Listing.vue'
export default {
mixins: [Listing],
props: [
'initialRows',
'initialColumns',
],
data() {
return {
rows: this.initialRows,
columns: this.initialColumns
}
}
}
</script>
Loading

0 comments on commit b5bbf28

Please sign in to comment.