@viur/shop-components 0.1.2 → 0.1.4-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.cjs ADDED
@@ -0,0 +1,23 @@
1
+ /* eslint-env node */
2
+ require("@rushstack/eslint-patch/modern-module-resolution")
3
+
4
+ module.exports = {
5
+ env: {
6
+ browser: true,
7
+ es2021: true,
8
+ node: true
9
+ },
10
+ root: true,
11
+ extends: ["plugin:vue/vue3-recommended", "plugin:prettier/recommended"],
12
+ plugins: ["vue", "prettier"],
13
+ parserOptions: {
14
+ ecmaVersion: "latest",
15
+ parser: "@typescript-eslint/parser"
16
+ },
17
+ rules: {
18
+ "vue/html-self-closing": 0,
19
+ "no-unused-vars": 1,
20
+ "vue/order-in-components": 0,
21
+ "vue/no-deprecated-slot-attribute":0,
22
+ }
23
+ }
@@ -14,9 +14,9 @@ jobs:
14
14
  steps:
15
15
  - name: Checkout
16
16
  uses: actions/checkout@v4
17
- - uses: actions/setup-node@v3
17
+ - uses: actions/setup-node@v4
18
18
  with:
19
- node-version: 16
19
+ node-version: 22
20
20
  registry-url: https://registry.npmjs.org/
21
21
  - run: npm ci
22
22
  - name: Publish npm package
@@ -35,7 +35,7 @@ jobs:
35
35
  run: |
36
36
  echo "${{ contains(github.ref_name, 'dev') }}"
37
37
  - name: Release
38
- uses: softprops/action-gh-release@v1
38
+ uses: softprops/action-gh-release@v2
39
39
  # if: "!startsWith(github.ref_name, 'v-test-')"
40
40
  with:
41
41
  generate_release_notes: true
package/.prettierrc ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/prettierrc",
3
+ "semi": false,
4
+ "singleQuote": false,
5
+ "singleAttributePerLine": true,
6
+ "printWidth": 120,
7
+ "bracketSpacing": true,
8
+ "bracketSameLine": false,
9
+ "arrowParens": "always",
10
+ "trailingComma": "none"
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viur/shop-components",
3
- "version": "0.1.2",
3
+ "version": "0.1.4-0",
4
4
  "description": "Frontend Vue components for the shop module of ViUR",
5
5
  "repository": {
6
6
  "type": "git",
package/src/Shop.vue CHANGED
@@ -171,24 +171,29 @@ watch(()=>shopStore.state.currentTab, (newVal,oldVal)=>{
171
171
  padding: var(--sl-spacing-medium);
172
172
  overflow: hidden;
173
173
  border-radius: var(--sl-border-radius-medium);
174
- grid-column: auto / span var(--shop-sidebar-columns);
175
174
  /* height has to be set or sidebar grows until infinity... */
176
175
  height: min-content;
176
+ grid-column: auto / span 12;
177
+ order: -1;
178
+ & > * + * {
179
+ margin-top: var(--sl-spacing-small);
180
+ }
177
181
  @media (min-width: 1024px) {
178
182
  position: sticky;
179
183
  max-height: calc(100vh - var(--viur-shop-sidebar-height-offset) - 2 * var(--padding));
180
184
  top: var(--padding);
181
185
  bottom: var(--padding);
186
+ grid-column: auto / span var(--shop-sidebar-columns);
187
+ order: unset;
182
188
  }
183
189
  }
184
190
 
185
191
  .viur-shop-stepper-wrap {
186
192
  display: flex;
187
193
  flex-direction: column;
188
- grid-column: auto / span var(--shop-main-columns);
189
-
190
- @media (max-width: 1024px) {
191
- grid-column: auto / span 12;
194
+ grid-column: auto / span 12;
195
+ @media (min-width: 1024px) {
196
+ grid-column: auto / span var(--shop-main-columns);
192
197
  }
193
198
 
194
199
  @media (max-width: 600px) {
@@ -12,25 +12,27 @@
12
12
 
13
13
  <sl-tab-panel :name="name">
14
14
  <template v-if="tab?.['loaded']">
15
-
16
-
15
+
16
+
17
17
  <component :is="tab['component']">
18
18
  <template #['template_'+name]>
19
- <slot :name="'template_'+name"></slot>
19
+ <slot :name="'template_'+name"></slot>
20
20
  </template>
21
-
21
+
22
22
  <template v-slot="slotProps">
23
- <sl-bar>
23
+ <sl-bar class="viur-shop-stepper-bar">
24
24
  <div slot="right">
25
25
  <span v-if="slotProps.hint" class="hint">{{ slotProps.hint }}</span>
26
26
  <sl-button
27
- :class="{'action-button-hint':slotProps.hint}"
28
- variant="primary"
29
- :disabled="active(slotProps)"
30
- @click="nextStep(slotProps)"
31
- :loading="tab['validating']"
27
+ :class="{'action-button-hint':slotProps.hint}"
28
+ variant="success"
29
+ size="large"
30
+ :disabled="active(slotProps)"
31
+ @click="nextStep(slotProps)"
32
+ :loading="tab['validating']"
32
33
  >
33
34
  {{slotProps.nextName}}
35
+ <sl-icon slot="suffix" name="chevron-right"></sl-icon>
34
36
  </sl-button>
35
37
  </div>
36
38
  </sl-bar>
@@ -77,7 +79,7 @@ function nextStep(obj){
77
79
  useTimeoutFn(() => {
78
80
  shopStore.navigateToNext()
79
81
  }, 300)
80
-
82
+
81
83
  }else{
82
84
  shopStore.state.tabs[shopStore.state.currentTab]['valid']=false
83
85
  shopStore.state.tabs[shopStore.state.currentTab]['validating']=false
@@ -97,6 +99,10 @@ function active(obj){
97
99
 
98
100
  <style scoped>
99
101
 
102
+ .viur-shop-stepper-bar {
103
+ margin-top: var(--shop-leaf-gap, var(--ignt-spacing-small))
104
+ }
105
+
100
106
  .hint{
101
107
  border:1px solid var(--sl-color-neutral-200);
102
108
  border-top-left-radius: var(--sl-input-border-radius-medium);
@@ -104,11 +110,13 @@ function active(obj){
104
110
  background-color: var(--sl-color-neutral-100);
105
111
  color:var(--sl-color-neutral-800);
106
112
  padding: 0 var(--sl-spacing-small);
107
- height: var(--ignt-basic-line-height);
108
-
113
+ height: auto;
114
+ min-height: var(--sl-input-height-large);
115
+ font-size: var(--sl-button-font-size-large);
116
+ line-height: calc(var(--sl-input-height-large) - var(--sl-input-border-width)* 2);
109
117
  }
110
118
  .action-button-hint::part(base){
111
119
  border-top-left-radius: 0;
112
120
  border-bottom-left-radius: 0;
113
121
  }
114
- </style>
122
+ </style>
@@ -1,10 +1,11 @@
1
1
  <template>
2
- <LoadingHandler :isLoading="!state.items.length">
3
- <h2 class="viur-shop-cart-sidebar-headline headline">Zusammenfassung</h2>
2
+ <LoadingHandler :isLoading="state.loading">
3
+ <h2 class="viur-shop-cart-sidebar-headline headline" v-html="$t('shop.summary_headline')"></h2>
4
4
  <div class="viur-shop-cart-sidebar-summary">
5
5
  <div class="viur-shop-cart-sidebar-summary-item" v-for="item in state.items">
6
6
  <template v-if="(!shopStore.state.showNodes && item.skel_type === 'leaf') || shopStore.state.showNodes">
7
- <div class="viur-shop-cart-sidebar-summary-item-amount" v-if="item.skel_type === 'leaf'">{{ item.quantity }}x
7
+ <div class="viur-shop-cart-sidebar-summary-item-amount" v-if="item.skel_type === 'leaf'">
8
+ {{ item.quantity }}&nbsp;&times;
8
9
  </div>
9
10
  <div class="viur-shop-cart-sidebar-summary-item-name" v-html="item.skel_type === 'node' ? item.name : item.shop_name"></div>
10
11
  <div class="viur-shop-cart-sidebar-summary-item-price">
@@ -15,18 +16,18 @@
15
16
  </template>
16
17
  </div>
17
18
  </div>
18
- <div class="viur-shop-cart-sidebar-info-line">
19
- <span>Zwischensumme</span>
19
+ <div class="viur-shop-cart-sidebar-info">
20
+ <span v-html="$t('shop.summary_subtotal')"></span>
20
21
  <sl-format-number lang="de" type="currency" currency="EUR" :value="state.cartTotal">
21
22
  </sl-format-number>
22
23
  </div>
23
- <div class="viur-shop-cart-sidebar-info-line">
24
- <span>Versandkosten</span>
24
+ <div class="viur-shop-cart-sidebar-info">
25
+ <span v-html="$t('shop.summary_shipping_total')"></span>
25
26
  <sl-format-number lang="de" type="currency" currency="EUR" :value="state.shippingTotal">
26
27
  </sl-format-number>
27
28
  </div>
28
29
  <div class="viur-shop-cart-shipping-item" v-if="shopStore.state.order?.cart?.dest?.shipping">
29
- <span>Lieferzeit </span>
30
+ <span v-html="$t('shop.summary_delivery_time')"></span>
30
31
  <span>
31
32
  {{
32
33
  shopStore.state.order?.cart?.dest?.shipping?.dest?.delivery_time_range ?
@@ -35,28 +36,28 @@
35
36
  }} {{ shopStore.state.order?.cart?.dest?.shipping?.dest?.delivery_time_range === 1 ? "Tag" : "Tage" }}
36
37
  </span>
37
38
  </div>
38
- <div class="viur-shop-cart-sidebar-info-line" v-if="shopStore.state.cartRoot.discount">
39
- <span>Rabatt</span>
39
+ <div class="viur-shop-cart-sidebar-info" v-if="shopStore.state.cartRoot.discount">
40
+ <span v-html="$t('shop.summary_discount')"></span>
40
41
  <sl-format-number lang="de" type="currency" currency="EUR" :value="state.discount">
41
42
  </sl-format-number>
42
43
  </div>
43
44
  <discount-input v-if="shopStore.state.currentTab!=='complete'"></discount-input>
44
- <div class="viur-shop-cart-sidebar-info-line">
45
+ <div class="viur-shop-cart-sidebar-info">
45
46
  </div>
46
-
47
- <div class="viur-shop-cart-sidebar-info-line total">
48
- <span>Gesamt:</span>
47
+
48
+ <div class="viur-shop-cart-sidebar-info viur-shop-cart-sidebar-info--total">
49
+ <span v-html="$t('shop.summary_total')"></span>
49
50
  <sl-format-number lang="de" type="currency" currency="EUR" :value="state.total">
50
51
  </sl-format-number>
51
52
  </div>
52
- <div class="viur-shop-cart-sidebar-info-line ">
53
- <span>inkl. MwSt:</span>
54
- <sl-format-number lang="de" type="currency" currency="EUR" :value="state.vat">
53
+ <div class="viur-shop-cart-sidebar-info " v-for="vatObj in state.vat">
54
+ <span v-html="$t('shop.summary_vat', {'percentage':calc_percent(vatObj.percentage) })"></span>
55
+ <sl-format-number lang="de" type="currency" currency="EUR" :value="vatObj.value">
55
56
  </sl-format-number>
56
57
  </div>
57
58
  <slot name="action-buttons" >
58
59
  <div class="viur-shop-cart-sidebar-btn-wrap" v-if="false && !shopStore.state.order?.['is_paid']">
59
- <sl-button variant="primary" size="medium">Bestellen</sl-button>
60
+ <sl-button variant="success" size="large">{{ $t("shop.summary_checkout") }}</sl-button>
60
61
  </div>
61
62
  </slot>
62
63
  </LoadingHandler>
@@ -74,7 +75,7 @@ const { fetchCart, addItem, state: cartState } = useCart();
74
75
 
75
76
  const state = reactive({
76
77
  items: computed(() => { return shopStore.state.cartList }),
77
- cartTotal: computed(() => {
78
+ cartTotal: computed(() => {
78
79
  let sum = state.items.reduce((acc,item)=>{
79
80
  if (item.skel_type==="leaf"){
80
81
  acc+=item.price.current *item.quantity
@@ -101,7 +102,7 @@ const state = reactive({
101
102
  return shopStore.state.cartRoot.total
102
103
  }),
103
104
  vat:computed(()=>{
104
- return shopStore.state.cartRoot.vat?.[0].value // why is this a list
105
+ return shopStore.state.cartRoot.vat
105
106
  }),
106
107
  sum:computed(()=>{
107
108
  let sum = state.items.reduce((acc,item)=>{
@@ -112,36 +113,47 @@ const state = reactive({
112
113
  return acc;
113
114
  },0)
114
115
  return sum
115
- })
116
+ }),
117
+ loading:false
116
118
  })
117
119
 
118
120
  onBeforeMount(() => {
121
+ state.loading=true
119
122
  if (!shopStore.state.cartList.length) {
120
- fetchCart()
123
+ fetchCart().then(()=>state.loading=false).catch(()=>state.loading=false)
124
+ }else{
125
+ state.loading=false
121
126
  }
122
127
  })
128
+
129
+ function calc_percent(val){
130
+ return new Intl.NumberFormat("de-DE", {
131
+ style: "percent",
132
+ minimumFractionDigits: 0,
133
+ maximumFractionDigits: 0
134
+ }).format(val);
135
+ }
136
+
137
+
123
138
  </script>
124
139
 
125
140
  <style scoped>
126
- .viur-shop-cart-sidebar-info-line {
141
+
142
+ .viur-shop-cart-sidebar-info {
127
143
  display: flex;
128
144
  flex-direction: row;
129
145
  flex-wrap: nowrap;
130
- margin: var(--sl-spacing-2x-small) 0;
131
-
132
- &.total {
133
- font-weight: 600;
134
- border-top: 1px solid var(--sl-color-neutral-300);
135
- border-bottom: 1px solid var(--sl-color-neutral-300);
136
- padding: var(--sl-spacing-x-small) 0;
137
- margin: var(--sl-spacing-small) 0;
138
- }
139
-
140
146
  span {
141
147
  margin-right: auto;
142
148
  }
143
149
  }
144
150
 
151
+ .viur-shop-cart-sidebar-info--total {
152
+ font-weight: 600;
153
+ border-top: 1px solid var(--sl-color-neutral-300);
154
+ padding-top: var(--sl-spacing-x-small);
155
+ }
156
+
145
157
  .viur-shop-cart-sidebar-btn-wrap {
146
158
  display: flex;
147
159
  flex-direction: column;
@@ -152,18 +164,17 @@ onBeforeMount(() => {
152
164
  }
153
165
  }
154
166
 
155
- .viur-shop-cart-sidebar-headline {
156
- margin: 0 0 var(--sl-spacing-large) 0;
157
- }
158
-
159
167
  .viur-shop-cart-sidebar-summary {
160
168
  display: flex;
161
169
  flex-direction: column;
162
170
  overflow: auto;
163
- margin-bottom: var(--sl-spacing-small);
164
171
  padding-right: 4px;
165
172
  margin-right: -4px;
166
173
 
174
+ & > *:not(:empty) + *:not(:empty) {
175
+ margin-top: var(--sl-spacing-small);
176
+ }
177
+
167
178
  &::-webkit-scrollbar {
168
179
  width: 3px;
169
180
  }
@@ -187,7 +198,6 @@ onBeforeMount(() => {
187
198
  flex-direction: row;
188
199
  flex-wrap: nowrap;
189
200
  gap: var(--sl-spacing-medium);
190
- margin-bottom: var(--sl-spacing-small);
191
201
  }
192
202
 
193
203
  .viur-shop-cart-sidebar-summary-item-name {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <loading-handler :isLoading="cartState.isLoading" :isUpdating="cartState.isUpdating">
3
- <div class="item-wrapper" v-if="state.items.length>0">
3
+ <div class="viur-shop-item-wrapper" v-if="state.items.length>0">
4
4
  <cart-item v-for="item in state.items" :item="item"
5
5
  :edit="!shopStore.state.order?.['is_checkout_in_progress']"
6
6
  >
@@ -13,12 +13,12 @@
13
13
  </template>
14
14
  </shop-alert>
15
15
  </loading-handler>
16
-
16
+
17
17
  <slot name="template_cart">
18
18
  </slot>
19
19
 
20
20
  <slot
21
- nextName="weiter"
21
+ :nextName="$t('shop.proceed-checkout')"
22
22
  :activefunction="()=>state.items.length>0"
23
23
  :nextfunction="()=>true"
24
24
  >
@@ -48,10 +48,11 @@ onBeforeMount(()=>{
48
48
 
49
49
  </script>
50
50
  <style scoped>
51
- .item-wrapper{
52
- display:flex;
53
- flex-direction: column;
54
- gap: 20px;
51
+
52
+ .viur-shop-item-wrapper {
53
+ display:flex;
54
+ flex-direction: column;
55
+ gap: var(--shop-leaf-gap, var(--ignt-spacing-small));
55
56
  }
56
57
 
57
58
  </style>
@@ -3,7 +3,7 @@
3
3
  <h2 class="viur-shop-cart-headline headline">{{ $t('shop.check_order')}}</h2>
4
4
  <div class="viur-shop-cart-address-wrap">
5
5
  <div class="viur-shop-cart-address">
6
- <div class="viur-shop-cart-address-headline">
6
+ <div class="viur-shop-user-data-headline">
7
7
  {{ $t('viur.shop.skeleton.cartnode.shipping_address') }}
8
8
  </div>
9
9
  <template v-if="state.shippingAddress">
@@ -17,7 +17,7 @@
17
17
  </template>
18
18
  </div>
19
19
  <div class="viur-shop-cart-address">
20
- <div class="viur-shop-cart-address-headline">
20
+ <div class="viur-shop-user-data-headline">
21
21
  {{ $t('viur.shop.skeleton.order.billing_address') }}
22
22
  </div>
23
23
  <template v-if="state.billingAddress">
@@ -271,7 +271,7 @@ sl-menu-item {
271
271
  margin-bottom: var(--sl-spacing-x-large);
272
272
  }
273
273
 
274
- .viur-shop-cart-address-headline {
274
+ .viur-shop-user-data-headline {
275
275
  display: flex;
276
276
  flex-direction: row;
277
277
  flex-wrap: nowrap;
@@ -1,24 +1,24 @@
1
1
  <template>
2
- <div class="viur-shop-cart-address-headline">
3
- {{ $t("skeleton.address.address_type.shipping") }}
2
+ <div class="viur-shop-user-data-headline">
3
+ {{ $t("skeleton.address.address_type.billing") }}
4
4
  </div>
5
-
6
- <address-form :formtype="addressState.billingIsShipping?'both':'shipping'">
5
+ <address-form :formtype="addressState.billingIsShipping?'both':'billing'">
7
6
  </address-form>
8
- <div>
9
- <sl-switch :checked="addressState.billingIsShipping" @sl-change="switchAddresses">{{ $t('shop.use_shipping_as_billing_address') }}</sl-switch>
10
- </div>
11
7
 
8
+ <sl-switch class="viur-shop-user-data-switch" :checked="addressState.billingIsShipping" @sl-change="switchAddresses">
9
+ {{ $t('shop.use_shipping_as_billing_address') }}
10
+ </sl-switch>
11
+
12
12
  <div v-show="!addressState.billingIsShipping">
13
- <div class="viur-shop-cart-address-headline">
14
- {{ $t("skeleton.address.address_type.billing") }}
13
+ <div class="viur-shop-user-data-headline">
14
+ {{ $t("skeleton.address.address_type.shipping") }}
15
15
  </div>
16
- <address-form formtype="billing" ></address-form>
16
+ <address-form formtype="shipping" >
17
+ </address-form>
17
18
  </div>
18
-
19
19
  <slot name="template_userdata">
20
20
  </slot>
21
-
21
+
22
22
  <slot
23
23
  nextName="weiter"
24
24
  :activefunction="()=>true"
@@ -46,9 +46,13 @@ function switchAddresses(event){
46
46
  }
47
47
 
48
48
  onBeforeMount(()=>{
49
- if (shopStore.state.cartRoot?.['shipping_address']?.['dest']?.['address_type']?.includes('billing') || !shopStore.state.cartRoot?.['shipping_address']?.['dest']){
49
+ if (!shopStore.state.order?.['billing_address']?.['dest']){
50
+ addressState.billingIsShipping = true //init
51
+ }
52
+ else if (shopStore.state.order?.['billing_address']?.['dest']?.['address_type']?.includes('shipping')){
50
53
  addressState.billingIsShipping = true
51
- }else{
54
+ }
55
+ else{
52
56
  addressState.billingIsShipping = false
53
57
  }
54
58
  })
@@ -70,7 +74,7 @@ async function nextStep(){
70
74
  </script>
71
75
 
72
76
  <style scoped>
73
- .viur-shop-cart-address-headline {
77
+ .viur-shop-user-data-headline {
74
78
  display: flex;
75
79
  flex-direction: row;
76
80
  flex-wrap: nowrap;
@@ -79,4 +83,4 @@ async function nextStep(){
79
83
  font-weight: 600;
80
84
  margin-bottom: var(--sl-spacing-medium);
81
85
  }
82
- </style>
86
+ </style>
@@ -29,22 +29,22 @@ const {state:addressState} = useAddress();
29
29
  const props = defineProps({
30
30
  formtype:{
31
31
  type:String,
32
- default:"shipping" // formtype: shipping, billing, both
32
+ default:"billing" // formtype: shipping, billing, both
33
33
  }
34
34
  })
35
35
 
36
36
  const state = reactive({
37
37
  formtype:computed(()=>{
38
- if (['shipping','both'].includes(props.formtype)){
39
- return "shipping"
38
+ if (['billing','both'].includes(props.formtype)){
39
+ return "billing"
40
40
  }
41
- return 'billing'
41
+ return 'shipping'
42
42
  }),
43
43
 
44
44
  action: computed(()=>{
45
45
  if (state.formtype ==='shipping' && shopStore.state.cartRoot?.['shipping_address']){
46
46
  return 'edit'
47
- } else if (props.formtype === 'billing' && shopStore.state.order?.['billing_address']){
47
+ } else if (state.formtype === 'billing' && shopStore.state.order?.['billing_address']){
48
48
  return 'edit'
49
49
  } else {
50
50
  return 'add'
@@ -54,7 +54,7 @@ const state = reactive({
54
54
  skelkey:computed(()=>{
55
55
  if (state.formtype === 'shipping' && shopStore.state.cartRoot?.['shipping_address']){
56
56
  return shopStore.state.cartRoot['shipping_address']?.['dest']?.['key']
57
- } else if (props.formtype === 'billing' && shopStore.state.order?.['billing_address']){
57
+ } else if (state.formtype === 'billing' && shopStore.state.order?.['billing_address']){
58
58
  return shopStore.state.order?.['billing_address']?.['dest']?.['key']
59
59
  }
60
60
  return null
@@ -78,14 +78,13 @@ function formChange(data){
78
78
 
79
79
  watch(()=>addressState.billingIsShipping, (newVal,oldVal)=>{
80
80
  if(oldVal && !newVal){
81
- if(shopStore.state.order?.['billing_address']){
82
- shopStore.state.order['billing_address'] = null
81
+ if(shopStore.state.cartRoot?.['shipping_address']){
82
+ shopStore.state.cartRoot['shipping_address'] = null
83
83
  }
84
-
85
- addressState[`billingForm`].state.skel = {'address_type':state.address_type, 'customer_type':'private'}
86
-
84
+ addressState[`shippingForm`].state.skel = {'address_type':state.address_type, 'customer_type':'private'}
87
85
  }
88
86
 
87
+ addressState[`${state.formtype}Form`].state.skel['address_type'] = state.address_type
89
88
  })
90
89
 
91
90
  </script>
@@ -46,6 +46,16 @@
46
46
  label="placeholder">
47
47
  </slot>
48
48
 
49
+ <slot boneName="email"
50
+ :widget="getBoneWidget(formState.structure['email']['type'])"
51
+ label="placeholder">
52
+ </slot>
53
+
54
+ <slot boneName="phone"
55
+ :widget="getBoneWidget(formState.structure['phone']['type'])"
56
+ label="placeholder">
57
+ </slot>
58
+
49
59
  </div>
50
60
  </template>
51
61
  <script setup>