@mixd-id/web-scaffold 0.1.240411023 → 0.1.240411024
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/package.json +3 -1
- package/src/components/404.vue +61 -0
- package/src/components/AccountIcon.vue +19 -0
- package/src/components/Cart.vue +192 -0
- package/src/components/CartIcon.vue +89 -0
- package/src/components/Checkout.vue +257 -0
- package/src/components/ColorPicker.vue +5 -0
- package/src/components/ContextMenu.vue +112 -201
- package/src/components/Modal.vue +2 -6
- package/src/components/SearchModal.vue +153 -0
- package/src/components/SvgEditor.vue +1 -1
- package/src/components/TreeMenu.vue +122 -0
- package/src/configs/web-page-builder.js +8 -0
- package/src/hooks/device.js +14 -0
- package/src/index.js +19 -8
- package/src/utils/helpers.mjs +1 -2
- package/src/widgets/CartSetting.vue +46 -0
- package/src/widgets/CheckoutSetting.vue +46 -0
- package/src/widgets/ComponentSetting2.vue +1 -2
- package/src/widgets/Dashboard/BarChart.vue +2 -1
- package/src/widgets/Dashboard.vue +42 -21
- package/src/widgets/SearchModalSetting.vue +70 -0
- package/src/widgets/StyleSetting.vue +175 -51
- package/src/widgets/WebPageBuilder.vue +1 -1
- package/src/components/SearchButton.vue +0 -57
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mixd-id/web-scaffold",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.240411024",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite serve",
|
|
7
7
|
"build": "vite build",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"require": "./src/utils/preset-selector.cjs",
|
|
38
38
|
"import": "./src/utils/preset-selector.mjs"
|
|
39
39
|
},
|
|
40
|
+
"./hooks/*": "./src/hooks/*",
|
|
40
41
|
"./preset-selector.cjs": "./src/utils/preset-selector.cjs",
|
|
41
42
|
"./preset-selector.js": "./src/utils/preset-selector.js",
|
|
42
43
|
"./preset-selector.mjs": "./src/utils/preset-selector.mjs",
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"redis": "^4.6.13",
|
|
71
72
|
"sequelize": "^6.37.6",
|
|
72
73
|
"tailwindcss": "^3.2.4",
|
|
74
|
+
"tinycolor2": "^1.6.0",
|
|
73
75
|
"vue": "^3.2.25",
|
|
74
76
|
"vue-chartjs": "^5.2.0",
|
|
75
77
|
"vue-router": "^4.0.14",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.el">
|
|
3
|
+
|
|
4
|
+
<div>
|
|
5
|
+
<h1>{{ title }}</h1>
|
|
6
|
+
<p>{{ description }}</p>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<slot>
|
|
10
|
+
<component v-if="items?.length > 0"
|
|
11
|
+
v-for="item in items"
|
|
12
|
+
:is="item.type"
|
|
13
|
+
:key="item.key"
|
|
14
|
+
:="item" />
|
|
15
|
+
|
|
16
|
+
<router-link v-else :to="{ path:'/' }" class="text-primary">
|
|
17
|
+
Back to Home
|
|
18
|
+
</router-link>
|
|
19
|
+
</slot>
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
|
|
28
|
+
props: {
|
|
29
|
+
|
|
30
|
+
description: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: 'The page you are looking for does not exist.'
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
title: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: 'Page Not Found'
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
items: Array
|
|
41
|
+
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
methods: {
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<style module>
|
|
54
|
+
|
|
55
|
+
.el{
|
|
56
|
+
@apply w-full max-w-[600px] mx-auto;
|
|
57
|
+
@apply flex flex-col gap-8 items-center justify-center;
|
|
58
|
+
@apply min-h-[60vh]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
</style>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.el">
|
|
3
|
+
|
|
4
|
+
<div v-if="readyState === 2" class="flex justify-center items-center min-h-[80vh]">
|
|
5
|
+
Loading...
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-else-if="!cart" class="flex flex-col gap-4 justify-center items-center min-h-[80vh]">
|
|
9
|
+
<div class="text-center">
|
|
10
|
+
<h1>Cart is Empty</h1>
|
|
11
|
+
<p class="max-w-[480px]">Your cart is empty, if you're interested in our products, browse products from our catalog by clicking button below.</p>
|
|
12
|
+
</div>
|
|
13
|
+
<router-link to="/" class="text-primary">Browse Catalog</router-link>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div v-else class="flex flex-col">
|
|
17
|
+
|
|
18
|
+
<div class="p-5">
|
|
19
|
+
<h3>Cart</h3>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="divide-y divide-text-50 px-3 bg-base-300 min-h-[80vh]">
|
|
23
|
+
<div v-for="item in cart.items" class="flex flex-row gap-2 p-2">
|
|
24
|
+
<Checkbox v-model="item.checked" />
|
|
25
|
+
<Image :src="item.imageUrl" class="w-[56px] aspect-square rounded-lg" />
|
|
26
|
+
<div class="flex-1 flex flex-col">
|
|
27
|
+
<small>{{ item.code }}</small>
|
|
28
|
+
<label>{{ item.name }}</label>
|
|
29
|
+
<div class="flex flex-row gap-2">
|
|
30
|
+
<strong>Rp. {{ item.price.toLocaleString() }}</strong>
|
|
31
|
+
<button type="button" class="text-primary text-xs" @click="remove(item)">
|
|
32
|
+
<svg width="11" height="11" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 80h-82.38l-34-56.75C306.1 8.827 291.4 0 274.6 0H173.4C156.6 0 141 8.827 132.4 23.25L98.38 80H16C7.125 80 0 87.13 0 96v16C0 120.9 7.125 128 16 128H32v320c0 35.35 28.65 64 64 64h256c35.35 0 64-28.65 64-64V128h16C440.9 128 448 120.9 448 112V96C448 87.13 440.9 80 432 80zM171.9 50.88C172.9 49.13 174.9 48 177 48h94c2.125 0 4.125 1.125 5.125 2.875L293.6 80H154.4L171.9 50.88zM352 464H96c-8.837 0-16-7.163-16-16V128h288v320C368 456.8 360.8 464 352 464zM224 416c8.844 0 16-7.156 16-16V192c0-8.844-7.156-16-16-16S208 183.2 208 192v208C208 408.8 215.2 416 224 416zM144 416C152.8 416 160 408.8 160 400V192c0-8.844-7.156-16-16-16S128 183.2 128 192v208C128 408.8 135.2 416 144 416zM304 416c8.844 0 16-7.156 16-16V192c0-8.844-7.156-16-16-16S288 183.2 288 192v208C288 408.8 295.2 416 304 416z"/></svg>
|
|
33
|
+
</button>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="flex flex-col items-end gap-1">
|
|
37
|
+
<Textbox class="w-[100px]"
|
|
38
|
+
v-model="item.qty"
|
|
39
|
+
item-class="text-center p-1">
|
|
40
|
+
<template #start>
|
|
41
|
+
<button type="button"
|
|
42
|
+
class="p-2"
|
|
43
|
+
@click="item.qty = (res => res < 1 ? 1 : res)(item.qty - 1)">
|
|
44
|
+
<svg width="14" height="14" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280H40c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h368C421.3 232 432 242.8 432 256z"/></svg>
|
|
45
|
+
</button>
|
|
46
|
+
</template>
|
|
47
|
+
<template #end>
|
|
48
|
+
<button type="button"
|
|
49
|
+
class="p-2"
|
|
50
|
+
@click="item.qty = (res => res > 5 ? 5 : res)(item.qty + 1)">
|
|
51
|
+
<svg width="14" height="14" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
52
|
+
</button>
|
|
53
|
+
</template>
|
|
54
|
+
</Textbox>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="p-5 py-3 bg-base-300 flex flex-row sticky bottom-0 border-t-[1px] border-text-50">
|
|
60
|
+
<div v-if="cart?.total > 0" class="flex flex-col flex-1 leading-3">
|
|
61
|
+
<small>Total</small>
|
|
62
|
+
<h5>Rp. {{ cart.total.toLocaleString() }}</h5>
|
|
63
|
+
</div>
|
|
64
|
+
<div v-else class="flex-1"></div>
|
|
65
|
+
<Button ref="checkoutBtn"
|
|
66
|
+
class="px-3"
|
|
67
|
+
:state="canCheckout ? 1 : -1"
|
|
68
|
+
@click="checkout">
|
|
69
|
+
Checkout
|
|
70
|
+
</Button>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
|
|
80
|
+
import axios from "axios";
|
|
81
|
+
import {invokeAfterIdle} from "../utils/helpers.mjs";
|
|
82
|
+
|
|
83
|
+
export default {
|
|
84
|
+
|
|
85
|
+
inject: [ 'alert' ],
|
|
86
|
+
|
|
87
|
+
computed: {
|
|
88
|
+
|
|
89
|
+
canCheckout(){
|
|
90
|
+
return this.apiUrl &&
|
|
91
|
+
this.cart && (this.cart.items ?? []).some(item => item.checked)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
props: {
|
|
97
|
+
|
|
98
|
+
apiUrl: String
|
|
99
|
+
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
methods: {
|
|
103
|
+
|
|
104
|
+
calculate(){
|
|
105
|
+
if(!this.cart) return
|
|
106
|
+
|
|
107
|
+
let subtotal = 0;
|
|
108
|
+
for(let item of this.cart.items){
|
|
109
|
+
if(!item.checked) continue
|
|
110
|
+
|
|
111
|
+
subtotal += item.qty * item.price
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.cart.total = subtotal
|
|
115
|
+
|
|
116
|
+
this.update()
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
checkout(){
|
|
120
|
+
this.$refs.checkoutBtn.setState(2)
|
|
121
|
+
axios.post(import.meta.env.VITE_API_HOST + this.apiUrl, {
|
|
122
|
+
action: 'checkout',
|
|
123
|
+
cart: this.cart
|
|
124
|
+
})
|
|
125
|
+
.then(res => {
|
|
126
|
+
if(res.data.target)
|
|
127
|
+
this.$router.push(res.data.target)
|
|
128
|
+
})
|
|
129
|
+
.catch(err => this.alert(err))
|
|
130
|
+
.finally(_ => this.$refs.checkoutBtn.resetState())
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
load(){
|
|
134
|
+
this.readyState = 2
|
|
135
|
+
axios.get(import.meta.env.VITE_API_HOST + this.apiUrl)
|
|
136
|
+
.then(res => {
|
|
137
|
+
this.cart = res.data
|
|
138
|
+
this.readyState = 1
|
|
139
|
+
})
|
|
140
|
+
.catch(err => {
|
|
141
|
+
this.readyState = -1
|
|
142
|
+
this.error = err
|
|
143
|
+
})
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
remove(item){
|
|
147
|
+
this.cart.items.splice(this.cart.items.indexOf(item), 1)
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
update: invokeAfterIdle(function(){
|
|
151
|
+
axios.post(import.meta.env.VITE_API_HOST + this.apiUrl, {
|
|
152
|
+
action: 'update',
|
|
153
|
+
cart: this.cart
|
|
154
|
+
})
|
|
155
|
+
}, 1000),
|
|
156
|
+
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
data(){
|
|
160
|
+
return {
|
|
161
|
+
cart: null,
|
|
162
|
+
readyState: 1,
|
|
163
|
+
error: null,
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
mounted() {
|
|
168
|
+
this.load()
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
watch: {
|
|
172
|
+
|
|
173
|
+
cart: {
|
|
174
|
+
deep: true,
|
|
175
|
+
handler(){
|
|
176
|
+
this.calculate()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
</script>
|
|
185
|
+
|
|
186
|
+
<style module>
|
|
187
|
+
|
|
188
|
+
.el{
|
|
189
|
+
@apply flex flex-col;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
</style>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button type="button"
|
|
3
|
+
:class="$style.comp"
|
|
4
|
+
@click="$refs.contextMenu.open($el)">
|
|
5
|
+
|
|
6
|
+
<div :class="$style.badge">3</div>
|
|
7
|
+
|
|
8
|
+
<slot name="icon">
|
|
9
|
+
<component v-if="items?.length > 0"
|
|
10
|
+
v-for="item in items"
|
|
11
|
+
:is="item.type"
|
|
12
|
+
:key="item.key"
|
|
13
|
+
:="item" />
|
|
14
|
+
|
|
15
|
+
<svg v-else
|
|
16
|
+
width="16"
|
|
17
|
+
height="16px"
|
|
18
|
+
class="fill-text"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M416 160h-72V120C344 53.83 290.2 0 224 0S104 53.83 104 120V160H32C14.33 160 0 174.3 0 192v240C0 476.2 35.82 512 80 512h288c44.18 0 80-35.82 80-80V192C448 174.3 433.7 160 416 160zM152 120C152 80.3 184.3 48 224 48s72 32.3 72 72V160h-144V120zM400 432c0 17.64-14.36 32-32 32h-288c-17.64 0-32-14.36-32-32v-224h56v56C104 277.3 114.8 288 128 288s24-10.75 24-24V208h144v56C296 277.3 306.8 288 320 288s24-10.75 24-24V208h56V432z"/></svg>
|
|
21
|
+
</slot>
|
|
22
|
+
|
|
23
|
+
<ContextMenu ref="contextMenu"
|
|
24
|
+
position="bottom-right"
|
|
25
|
+
class="border-transparent">
|
|
26
|
+
<div class="flex flex-col min-w-[300px] divide-y divide-text-50">
|
|
27
|
+
|
|
28
|
+
<div class="" @click.stop>
|
|
29
|
+
<div class="p-5 py-3 flex flex-row items-center">
|
|
30
|
+
<div class="flex-1">
|
|
31
|
+
<h5>Shopping Cart</h5>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div>
|
|
36
|
+
<div class="min-h-[160px] flex items-center justify-center">
|
|
37
|
+
<label class="text-text-400">
|
|
38
|
+
No item in cart
|
|
39
|
+
</label>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="text-center p-3">
|
|
45
|
+
<router-link to="/cart" type="button" class="text-primary">Open Cart</router-link>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
</div>
|
|
49
|
+
</ContextMenu>
|
|
50
|
+
|
|
51
|
+
</button>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script>
|
|
55
|
+
|
|
56
|
+
import {componentMixin} from "../mixin/component";
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
|
|
60
|
+
mixins: [ componentMixin ],
|
|
61
|
+
|
|
62
|
+
props: {
|
|
63
|
+
|
|
64
|
+
items: Array
|
|
65
|
+
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
methods: {
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<style module>
|
|
78
|
+
|
|
79
|
+
.comp{
|
|
80
|
+
@apply relative;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.badge{
|
|
84
|
+
@apply rounded-full w-[16px] h-[16px] bg-text text-white pointer-events-none;
|
|
85
|
+
@apply absolute bottom-[-6px] right-[-12px];
|
|
86
|
+
@apply flex items-center justify-center text-xs;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
</style>
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.el">
|
|
3
|
+
|
|
4
|
+
<div v-if="readyState === 2" class="flex justify-center items-center min-h-[80vh]">
|
|
5
|
+
Loading...
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-else-if="!order" class="flex flex-col gap-4 justify-center items-center min-h-[80vh] p-8">
|
|
9
|
+
<div class="text-center">
|
|
10
|
+
<h1>Cart is Empty</h1>
|
|
11
|
+
<p class="max-w-[480px]">Your order is empty, if you're interested in our products, browse products from our catalog by clicking button below.</p>
|
|
12
|
+
</div>
|
|
13
|
+
<router-link to="/" class="text-primary">Browse Catalog</router-link>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div v-else class="flex flex-col md:flex-row md:gap-8 min-h-[100vh]">
|
|
17
|
+
|
|
18
|
+
<div class="flex-1 flex flex-col gap-5">
|
|
19
|
+
<div v-if="order.customerId">
|
|
20
|
+
<div class="px-5">
|
|
21
|
+
<small class="text-text-400">Customer</small>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="bg-base-300 flex flex-col p-5 py-3">
|
|
24
|
+
<strong>{{ order.customerName }}</strong>
|
|
25
|
+
<label>{{ order.mobileNumber }}</label>
|
|
26
|
+
<small>{{ order.email }}</small>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div v-else>
|
|
31
|
+
<div class="px-5">
|
|
32
|
+
<small class="text-text-400">Customer</small>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="bg-base-300 flex flex-col gap-3 p-5 py-3">
|
|
35
|
+
<div>
|
|
36
|
+
<small>Name</small>
|
|
37
|
+
<Textbox v-model="order.customerName" />
|
|
38
|
+
</div>
|
|
39
|
+
<div>
|
|
40
|
+
<small>Mobile Number</small>
|
|
41
|
+
<Textbox v-model="order.mobileNumber" maxlength="20" />
|
|
42
|
+
</div>
|
|
43
|
+
<div>
|
|
44
|
+
<small>Email</small>
|
|
45
|
+
<Textbox v-model="order.email" maxlength="50" />
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div>
|
|
51
|
+
<div class="px-5 flex flex-row gap-2">
|
|
52
|
+
<small class="text-text-400 flex-1">Delivery</small>
|
|
53
|
+
<button type="button" class="text-primary text-sm"
|
|
54
|
+
@click="$refs.deliveryAddress.open()">
|
|
55
|
+
Choose Address
|
|
56
|
+
</button>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="bg-base-300 flex flex-col p-5 py-3">
|
|
59
|
+
|
|
60
|
+
<div v-if="order.deliveryAddressId">
|
|
61
|
+
<p>{{ order.deliveryAddress }}</p>
|
|
62
|
+
<p>
|
|
63
|
+
{{ order.deliveryProvinceName }}
|
|
64
|
+
-
|
|
65
|
+
{{ order.deliveryCityName}}
|
|
66
|
+
</p>
|
|
67
|
+
<p>
|
|
68
|
+
{{ order.deliveryDistrictName }}
|
|
69
|
+
-
|
|
70
|
+
{{ order.deliverySubdistrictName }}
|
|
71
|
+
-
|
|
72
|
+
{{ order.deliveryPostalCode }}
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div>
|
|
80
|
+
<div class="px-5 flex flex-row gap-2">
|
|
81
|
+
<small class="text-text-400">Payment</small>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="bg-base-300 p-5 py-3 grid grid-cols-2 gap-3">
|
|
84
|
+
|
|
85
|
+
<Radio v-for="paymentType of paymentTypes"
|
|
86
|
+
:class="`${$style.paymentType}${paymentType.id === order.paymentTypeId ? ' ' + $style.paymentTypeSelected : ''}`"
|
|
87
|
+
v-model.number="order.paymentTypeId"
|
|
88
|
+
:value="paymentType.id"
|
|
89
|
+
:custom="true">
|
|
90
|
+
{{ paymentType.name }}
|
|
91
|
+
</Radio>
|
|
92
|
+
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div class="flex md:hidden p-5 py-3 bg-base-300 flex-row sticky bottom-0 border-t-[1px] border-text-50">
|
|
98
|
+
<div v-if="order?.total > 0" class="flex flex-col flex-1 leading-3">
|
|
99
|
+
<small>Total</small>
|
|
100
|
+
<h5>Rp. {{ order.total.toLocaleString() }}</h5>
|
|
101
|
+
</div>
|
|
102
|
+
<div v-else class="flex-1"></div>
|
|
103
|
+
<Button ref="paymentBtn"
|
|
104
|
+
class="px-3"
|
|
105
|
+
:state="canPayment ? 1 : -1"
|
|
106
|
+
@click="payment">
|
|
107
|
+
Payment
|
|
108
|
+
</Button>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="hidden md:flex flex-col w-[300px]">
|
|
112
|
+
|
|
113
|
+
<div class="flex flex-row gap-2 px-3">
|
|
114
|
+
<small class="text-text-400 flex-1">Summary</small>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="bg-base-300 min-h-[200px]">
|
|
117
|
+
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<Modal ref="deliveryAddress" width="480" height="600">
|
|
125
|
+
<template v-slot:head>
|
|
126
|
+
<div class="relative p-5">
|
|
127
|
+
<h3>Select Address</h3>
|
|
128
|
+
<div class="absolute top-0 right-0 p-2">
|
|
129
|
+
<button type="button" class="p-2" @click="$refs.deliveryAddress.close()">
|
|
130
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
131
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
132
|
+
</svg>
|
|
133
|
+
</button>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</template>
|
|
137
|
+
|
|
138
|
+
<template #default="{ context }">
|
|
139
|
+
<div class="flex-1 p-5 flex flex-col">
|
|
140
|
+
|
|
141
|
+
<div v-for="deliveryAddress in deliveryAddresses">
|
|
142
|
+
{{ deliveryAddress }}
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<button type="button" class="p-3 text-center">
|
|
146
|
+
New Address
|
|
147
|
+
</button>
|
|
148
|
+
|
|
149
|
+
</div>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<template v-slot:foot>
|
|
153
|
+
<div class="p-5">
|
|
154
|
+
|
|
155
|
+
</div>
|
|
156
|
+
</template>
|
|
157
|
+
</Modal>
|
|
158
|
+
|
|
159
|
+
</div>
|
|
160
|
+
</template>
|
|
161
|
+
|
|
162
|
+
<script>
|
|
163
|
+
|
|
164
|
+
import axios from "axios";
|
|
165
|
+
|
|
166
|
+
export default {
|
|
167
|
+
|
|
168
|
+
computed: {
|
|
169
|
+
|
|
170
|
+
canPayment(){
|
|
171
|
+
return this.apiUrl &&
|
|
172
|
+
this.order
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
props: {
|
|
178
|
+
|
|
179
|
+
apiUrl: String
|
|
180
|
+
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
methods: {
|
|
184
|
+
|
|
185
|
+
load(uid){
|
|
186
|
+
this.readyState = 2
|
|
187
|
+
axios.get(import.meta.env.VITE_API_HOST + this.apiUrl, {
|
|
188
|
+
params: {
|
|
189
|
+
uid
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
.then(res => {
|
|
193
|
+
this.order = res.data.order
|
|
194
|
+
this.deliveryAddresses = res.data.deliveryAddresses
|
|
195
|
+
this.paymentTypes = res.data.paymentTypes
|
|
196
|
+
this.readyState = 1
|
|
197
|
+
})
|
|
198
|
+
.catch(err => {
|
|
199
|
+
this.readyState = -1
|
|
200
|
+
this.error = err
|
|
201
|
+
})
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
payment(){
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
data(){
|
|
211
|
+
return {
|
|
212
|
+
order: null,
|
|
213
|
+
paymentTypes: null,
|
|
214
|
+
deliveryAddresses: null,
|
|
215
|
+
readyState: 1,
|
|
216
|
+
error: null
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
mounted() {
|
|
221
|
+
if(this.$editMode.value > 0){
|
|
222
|
+
this.load('dummy')
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
watch: {
|
|
227
|
+
|
|
228
|
+
'$route.query.uid': {
|
|
229
|
+
immediate: true,
|
|
230
|
+
handler(uid){
|
|
231
|
+
if(uid){
|
|
232
|
+
this.load(uid)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
</script>
|
|
242
|
+
|
|
243
|
+
<style module>
|
|
244
|
+
|
|
245
|
+
.el{
|
|
246
|
+
@apply max-w-[900px] mx-auto;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.paymentType{
|
|
250
|
+
@apply border-[1px] border-text-50 rounded-lg;
|
|
251
|
+
@apply p-2 text-sm;
|
|
252
|
+
}
|
|
253
|
+
.paymentTypeSelected{
|
|
254
|
+
@apply border-primary;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
</style>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="$style.comp">
|
|
3
|
+
|
|
3
4
|
<div :class="circleClass" :style="circleStyle"
|
|
4
5
|
@click="mode === 'hex' ? $refs.inputColor.click() : $refs.contextMenu.open($refs.btn)"
|
|
5
6
|
ref="btn"></div>
|
|
7
|
+
|
|
6
8
|
<input type="color" :class="$style.inputColor" ref="inputColor"
|
|
7
9
|
@change="select($refs.inputColor.value)"/>
|
|
8
10
|
|
|
@@ -71,6 +73,8 @@ export default{
|
|
|
71
73
|
|
|
72
74
|
valueType: String,
|
|
73
75
|
|
|
76
|
+
itemClass: String
|
|
77
|
+
|
|
74
78
|
},
|
|
75
79
|
|
|
76
80
|
methods: {
|
|
@@ -104,6 +108,7 @@ export default{
|
|
|
104
108
|
circleClass(){
|
|
105
109
|
return [
|
|
106
110
|
this.$style.circle,
|
|
111
|
+
this.itemClass,
|
|
107
112
|
this.mode === 'class' ?
|
|
108
113
|
(this.modelValue ?? '').replace('text-', 'bg-').replace('border-', 'bg-') :
|
|
109
114
|
''
|