@ozdao/prometheus-framework 0.2.58 → 0.2.59

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ozdao/prometheus-framework",
3
- "version": "0.2.58",
3
+ "version": "0.2.59",
4
4
  "description": "Web3 Framework focused on user experience and ease of development.",
5
5
  "author": "OZ DAO <hello@ozdao.dev>",
6
6
  "license": "GPL-3.0-or-later",
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <div>
3
+ <Button :submit="openPublicationPopup" class="bg-main button-small radius-extra button">
4
+ Check ticket
5
+ </Button>
6
+
7
+ <Popup title="Добавить участника" @close-popup="closePublicationPopup" :isPopupOpen="isPublicationPopup"
8
+ class="w-max-30r h-max-30r t-left pd-big bg-white radius-big">
9
+ <h3 class="mn-b-small">Final Touches</h3>
10
+
11
+ <div style="border: 2px solid black" class="h-100">
12
+ <QrcodeStream :track="paintBoundingBox" @detect="onDetect" @error="onError"></QrcodeStream>
13
+ </div>
14
+ </Popup>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup>
19
+ // Deps
20
+ import { ref } from 'vue'
21
+ import { QrcodeStream } from 'vue-qrcode-reader'
22
+
23
+ // In components
24
+ import Popup from '@pf/src/components/Popup/Popup.vue'
25
+ import Button from '@pf/src/components/Button/Button.vue'
26
+
27
+ // Methods
28
+ import * as tickets from '@pf/src/modules/events/store/tickets'
29
+
30
+ const isPublicationPopup = ref(false)
31
+
32
+ function openPublicationPopup() {
33
+ isPublicationPopup.value = true
34
+ }
35
+
36
+ function closePublicationPopup() {
37
+ isPublicationPopup.value = false
38
+ }
39
+
40
+ const result = ref(null)
41
+ async function onDetect(detectedCodes) {
42
+ result.value = detectedCodes.map((code) => code.rawValue)
43
+
44
+ try {
45
+ const qrcode = result.value[0] || ''
46
+ console.log('Получено значение qrcode:', qrcode);
47
+
48
+ if (!qrcode) {
49
+ throw new Error('неудалось прочитать qrcode');
50
+ }
51
+
52
+ const response = await tickets.actions.update({
53
+ _id: qrcode,
54
+ status: 'used',
55
+ })
56
+
57
+ console.log('Обновлено значение ticket.status:', response)
58
+
59
+ alert('Билет проверен');
60
+
61
+ closePublicationPopup()
62
+ } catch (e) {
63
+ alert('Билет не найден или уже использован');
64
+
65
+ console.error('Ошибка при обновлении ticket.status:', e.message)
66
+ }
67
+ }
68
+
69
+ function onError(err) {
70
+ error.value = `[${err.name}]: `
71
+
72
+ if (err.name === 'NotAllowedError') {
73
+ error.value += 'you need to grant camera access permission'
74
+ } else if (err.name === 'NotFoundError') {
75
+ error.value += 'no camera on this device'
76
+ } else if (err.name === 'NotSupportedError') {
77
+ error.value += 'secure context required (HTTPS, localhost)'
78
+ } else if (err.name === 'NotReadableError') {
79
+ error.value += 'is the camera already in use?'
80
+ } else if (err.name === 'OverconstrainedError') {
81
+ error.value += 'installed cameras are not suitable'
82
+ } else if (err.name === 'StreamApiNotSupportedError') {
83
+ error.value += 'Stream API is not supported in this browser'
84
+ } else if (err.name === 'InsecureContextError') {
85
+ error.value += 'Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.'
86
+ } else {
87
+ error.value += err.message
88
+ }
89
+ }
90
+
91
+ function paintBoundingBox(detectedCodes, ctx) {
92
+ for (const detectedCode of detectedCodes) {
93
+ const {
94
+ boundingBox: { x, y, width, height }
95
+ } = detectedCode
96
+
97
+ ctx.lineWidth = 2
98
+ ctx.strokeStyle = '#007bff'
99
+ ctx.strokeRect(x, y, width, height)
100
+ }
101
+ }
102
+ </script>
103
+
104
+ <style scoped>
105
+ /* Existing styles can stay unchanged */
106
+ </style>
@@ -128,6 +128,10 @@
128
128
  @updateTicket="handleTicketUpdate"
129
129
  />
130
130
 
131
+ <!-- <img v-if="qrcode" :src="qrcode" class="w-8r h-8r" /> -->
132
+
133
+ <!-- <ButtonCheck class="w-100 pd-medium mn-auto" /> -->
134
+
131
135
  <section>
132
136
  <component
133
137
  v-if="event && event.content"
@@ -169,13 +173,14 @@
169
173
  import HeroEvent from '@pf/src/modules/events/components/sections/HeroEvent.vue';
170
174
  import SectionMainGuest from '@pf/src/modules/events/components/sections/SectionMainGuest.vue';
171
175
  import SectionSpecialGuests from '@pf/src/modules/events/components/sections/SectionSpecialGuests.vue'
172
- import SectionLineUp from '@pf/src/modules/events/components/sections/SectionLineUp.vue';
176
+ import SectionLineUp from '@pf/src/modules/events/components/sections/SectionLineup.vue';
173
177
  import SectionPreviousEvents from '@pf/src/modules/events/components/sections/SectionPreviousEvents.vue';
174
178
 
175
179
 
176
180
  import CardEvent from '@pf/src/modules/events/components/blocks/CardEvent.vue';
177
181
  import SkeletonEvent from '@pf/src/modules/icons/skeletons/SkeletonEvent.vue'
178
182
  import ButtonJoin from '@pf/src/modules/events/components/elements/ButtonJoin.vue';
183
+ // import ButtonCheck from '@pf/src/modules/events/components/elements/ButtonCheck.vue'
179
184
  import Comments from '@pf/src/modules/community/components/sections/Comments.vue';
180
185
 
181
186
  import Image from '@pf/src/modules/constructor/components/elements/Image.vue';
@@ -187,9 +192,13 @@
187
192
  import { useRoute } from 'vue-router';
188
193
 
189
194
  const route = useRoute();
195
+ const qrcode = ref(null);
190
196
 
191
197
  const handleTicketUpdate = ({ ticket, hasTicket, targetId }) => {
192
198
  tickets.mutations.handleTicketUpdate(event.value, ticket, hasTicket, targetId);
199
+ console.log('HANDLE TICKET UPDATE', ticket, event.value);
200
+
201
+ qrcode.value = ticket.qrcode;
193
202
  };
194
203
 
195
204
 
@@ -1,3 +1,5 @@
1
+ const QRCode = require("qrcode");
2
+
1
3
  const controllerFactory = (db) => {
2
4
  const Ticket = db.ticket;
3
5
 
@@ -42,6 +44,17 @@ const controllerFactory = (db) => {
42
44
 
43
45
  try {
44
46
  const data = await newTicket.save();
47
+
48
+ // Working with qrcode
49
+ const qrData = data._id.toString();
50
+ const qrCode = await QRCode.toDataURL(qrData);
51
+
52
+ data.status = "unused";
53
+ data.qrcode = qrCode;
54
+
55
+ // Updated ticked with generated qrcode
56
+ await data.save();
57
+
45
58
  res.send(data);
46
59
  } catch (err) {
47
60
  res.status(500).send({ errorCode: "SERVER_ERROR" });
@@ -50,12 +63,28 @@ const controllerFactory = (db) => {
50
63
 
51
64
  const update = async (req, res) => {
52
65
  try {
53
- const ticket = await Ticket.findByIdAndUpdate(req.body._id, req.body, { new: true });
66
+ const { _id } = req.body;
67
+
68
+ // Поиск билета по ID
69
+ const ticket = await Ticket.findById(_id);
70
+
71
+ // Если билет не найден
54
72
  if (!ticket) {
55
73
  return res.status(404).send({ errorCode: "TICKET_NOT_FOUND" });
56
74
  }
57
- res.send(ticket);
75
+
76
+ // Проверка статуса билета
77
+ if (ticket.status === "used") {
78
+ return res.status(500).send({ errorCode: "TICKET_ALREADY_USED" });
79
+ }
80
+
81
+ // Обновление билета
82
+ const updatedTicket = await Ticket.findByIdAndUpdate(_id, req.body, { new: true });
83
+
84
+ // Отправка обновленного билета
85
+ res.send(updatedTicket);
58
86
  } catch (err) {
87
+ // Обработка ошибки сервера
59
88
  res.status(500).send({ errorCode: "SERVER_ERROR" });
60
89
  }
61
90
  };
@@ -23,6 +23,14 @@ module.exports = (mongoose) => {
23
23
  type: String,
24
24
  default: 'participant'
25
25
  },
26
+ qrcode: {
27
+ type: String,
28
+ },
29
+ status: {
30
+ type: String,
31
+ enum: ["unused", "used"],
32
+ deafult: "unused",
33
+ },
26
34
  });
27
35
 
28
36
  TicketSchema.index({ user: 1, type: 1, target: 1 });
@@ -11,7 +11,7 @@
11
11
  class="w-100 flex-nowrap flex-v-center flex"
12
12
  >
13
13
  <img
14
- v-if="owner.target.profile.photo.length > 0 && type !== 'short'"
14
+ v-if="owner.target.profile.photo?.length > 0 && type !== 'short'"
15
15
  :src="(FILE_SERVER_URL || '') + owner.target.profile.photo"
16
16
  class="radius-medium object-fit-cover mn-r-thin i-thin"
17
17
 
@@ -14,7 +14,7 @@ module.exports = function applyOwnershipSchema(schema,db) {
14
14
  creator: {
15
15
  hidden: {
16
16
  type: Boolean,
17
- required: true
17
+ default: false
18
18
  },
19
19
  type: {
20
20
  type: String,
@@ -1,8 +1,17 @@
1
1
  <template>
2
2
  <div>
3
- <header class="mn-b-medium flex-v-center flex-nowrap flex">
4
- <h2 class="mn-r-medium">Create Order</h2>
5
- </header>
3
+ <Block class="mn-b-thin">
4
+ <header class="flex-v-center flex-nowrap flex">
5
+ <h2 class="mn-r-auto">Create Order</h2>
6
+ <Button
7
+ :submit="onSubmit"
8
+ :callback="redirectTo"
9
+ class="pd-small radius-big bg-main t-black uppercase t-medium"
10
+ >
11
+ Add Order
12
+ </Button>
13
+ </header>
14
+ </Block>
6
15
 
7
16
  <Popup
8
17
  title="Добавить участника"
@@ -51,7 +60,7 @@
51
60
  </Popup>
52
61
 
53
62
  <Block
54
- title="Invetory Sheet"
63
+ title="Positions"
55
64
  :actions="[{
56
65
  label: '+',
57
66
  function: () => openProductsPopup()
@@ -76,28 +85,40 @@
76
85
  class="mn-b-thin pd-thin radius-medium bg-white"
77
86
  />
78
87
  </Block>
79
- <!--
80
- <FormOrderDetails
81
- :order="orders.state.current"
82
- @create="handleCreate"
83
- class="bg-grey pd-medium radius-big mn-b-semi"
84
- /> -->
85
-
86
-
87
- <div class="mn-thinw-100 flex-v-center flex block">
88
- <p class="p-big">Сумма к оплате:
89
- <span v-if="order?.info?.delivery === 'Самовывоз'" class="p-big t-semi">{{ orderTotalPrice / 100 }} ₽</span>
90
- <span v-if="order?.info?.delivery === 'Курьером'" class="p-big t-semi">{{ orderTotalPrice / 100 + 350 }} ₽</span>
91
- <span v-if="order?.info?.delivery === 'Почтой'" class="p-big t-semi">{{ orderTotalPrice / 100 + 550 }} ₽</span>
92
- (Заказ {{orderTotalPrice / 100}} ₽ + доставка
93
- <span v-if="order?.info?.delivery === 'Самовывоз'" >0</span>
94
- <span v-if="order?.info?.delivery === 'Курьером'" >350</span>
95
- <span v-if="order?.info?.delivery === 'Почтой'">550</span>
96
- ₽)
97
- </p>
98
-
99
- <button class="mn-l-auto button">Запросить онлайн</button>
100
- </div>
88
+
89
+ <Block
90
+ title="Client"
91
+ class="mn-b-semi"
92
+ >
93
+ <Field
94
+ v-model:field="orders.state.current.client.name"
95
+ label="Client"
96
+ placeholder="Enter client name"
97
+ class="bg-white pd-medium radius-small mn-b-thin"
98
+ />
99
+
100
+ <Field
101
+ v-model:field="orders.state.current.comment"
102
+ label="Comment"
103
+ placeholder="Enter comment"
104
+ class="bg-white pd-medium radius-small mn-b-thin"
105
+ />
106
+
107
+ <!-- <FormClientDetails
108
+ :order="orders.state.current"
109
+ class="bg-white"
110
+ /> -->
111
+
112
+ </Block>
113
+
114
+ <Block
115
+ class="mn-b-semi"
116
+ >
117
+ <div class="h3 flex">
118
+ <span class="mn-r-auto t-transp">In total</span>
119
+ <span>{{ cartTotalPrice }} {{returnCurrency()}} </span >
120
+ </div>
121
+ </Block>
101
122
  </div>
102
123
 
103
124
 
@@ -106,24 +127,34 @@
106
127
  <script setup="props">
107
128
  // Import Vue functionality
108
129
  import { computed, ref, defineProps, onMounted, reactive, toRefs, watch } from 'vue'
109
- import { useRoute } from 'vue-router'
130
+ import { useRoute,useRouter } from 'vue-router'
110
131
 
111
132
  import Feed from '@pf/src/components/Feed/Feed.vue'
133
+
134
+ import Field from '@pf/src/components/Field/Field.vue'
135
+ import Button from "@pf/src/components/Button/Button.vue";
112
136
  import Popup from '@pf/src/components/Popup/Popup.vue';
113
137
  import Block from '@pf/src/components/Block/Block.vue';
114
138
 
115
139
  import CardOrderItem from '@pf/src/modules/orders/components/blocks/CardOrderItem.vue'
116
-
117
140
  import CardPosition from '@pf/src/modules/products/components/blocks/CardPosition.vue';
118
-
119
141
 
142
+ import FormClientDetails from '@pf/src/modules/orders/components/sections/FormClientDetails.vue'
120
143
  // Import your store
144
+ import * as auth from '@pf/src/modules/auth/store/auth';
121
145
  import * as globals from '@pf/src/modules/globals/store/globals';
122
146
  import * as orders from '@pf/src/modules/orders/store/orders';
123
147
  import * as products from '@pf/src/modules/products/store/products';
124
148
 
125
149
  // Accessing router
126
150
  const route = useRoute()
151
+ const router = useRouter()
152
+
153
+ let cartTotalPrice = computed(() => {
154
+ return Number(orders.state.current.positions.reduce((total, product) => {
155
+ return total + product.price * product.quantity;
156
+ }, 0));
157
+ })
127
158
 
128
159
  // Popup
129
160
  const isOpenProductsPopup = ref(false);
@@ -139,6 +170,30 @@
139
170
  // Data
140
171
  let order = ref(null)
141
172
 
173
+ function onSubmit() {
174
+
175
+ orders.state.current.creator = {
176
+ type: 'user',
177
+ target: auth.state.user._id
178
+ }
179
+
180
+ orders.state.current.owner = {
181
+ type: 'organization',
182
+ target: route.params._id,
183
+ }
184
+
185
+ orders.actions.create(orders.state.current)
186
+ }
187
+
188
+ function redirectTo () {
189
+ router.push({
190
+ name: 'Backoffice Orders',
191
+ params: {
192
+ _id: route.params._id
193
+ }
194
+ })
195
+ }
196
+
142
197
  onMounted(async () => {
143
198
  // await orders.actions.fetchOrder(route.params.id) // Implement this action in your store
144
199
 
@@ -149,7 +149,7 @@
149
149
  v-if="orders.state.current.status_history"
150
150
  :statusHistory="orders.state.current.status_history"
151
151
  :statusCurrent="orders.state.current.status"
152
- :edit="route.name === 'AdminOrderEdit'"
152
+ :edit="route.name === 'Order Edit'"
153
153
  />
154
154
 
155
155
  <!-- <button
@@ -196,7 +196,7 @@
196
196
  :username="
197
197
  route.name === 'Order Status' ? order.user?.name || 'User' : 'Weeder Support'
198
198
  "
199
- :chatID="order._id"
199
+ :chatID="route.params.order"
200
200
  class="radius-semi bg-white o-hidden"
201
201
  />
202
202
 
@@ -232,37 +232,38 @@
232
232
 
233
233
  onMounted(async()=>{
234
234
  order.value = await orders.actions.read({_id: route.params.order})
235
+ order.value = order.value[0]
235
236
 
236
237
  productsOrganization.value = await products.actions.read({
237
- organization: order.value[0].owner.target
238
+ organization: order.value?.owner.target._id
238
239
  });
239
240
 
240
241
  orderOrganization.value = await organizations.actions.read({
241
- _id: order.value[0].owner.target,
242
- // location: globals.state.position?.location,
242
+ _id: order.value?.owner.target._id,
243
+ location: globals.state.position?.location,
243
244
  });
244
245
 
245
246
  })
246
247
 
247
248
  let cartTotalPrice = computed(() => {
248
- return Number(order.value[0]?.positions.reduce((total, product) => {
249
+ return Number(order.value?.positions.reduce((total, product) => {
249
250
  return total + product.price * product.quantity;
250
251
  }, 0));
251
252
  })
252
253
 
253
254
  let cartTotalAmount = computed(() => {
254
- return Number(order.value[0]?.positions.reduce((total, product) => {
255
+ return Number(order.value?.positions.reduce((total, product) => {
255
256
  return total + product.quantity;
256
257
  }, 0));
257
258
  })
258
259
 
259
260
  let orderProducts = computed(() => {
260
- return order.value[0]?.positions.map(({ _id, quantity }) => {
261
+ return order.value?.positions.map(({ _id, quantity }) => {
261
262
 
262
263
  const product = productsOrganization.value.find(product => product._id === _id)
263
264
 
264
265
  console.log(product)
265
- console.log(productOrganization)
266
+ console.log(productsOrganization)
266
267
 
267
268
  return {
268
269
  name: product.name,
@@ -26,18 +26,39 @@
26
26
  class="cols-3 gap-thin"
27
27
  >
28
28
 
29
- <div
30
- v-for="order in orders.state.all"
31
- class="bg-grey pd-small radius-big"
32
- >
33
- Status: {{order.status}}
29
+ <router-link
30
+ v-for="order in orders.state.all"
31
+ :to="{
32
+ name: 'Order Edit',
33
+ params: {
34
+ order: order._id
34
35
 
36
+ }
37
+ }"
38
+ class="bg-grey radius-big"
39
+ >
40
+ <CardHeader
41
+ :class="{
42
+ 'mn-b-small pd-medium': type !== 'short',
43
+ 'flex-child-order-last flex-child mn-l-small': type === 'short',
44
+ }"
45
+ :entity="order"
46
+ :entityType="'order'"
47
+ :user="auth.state.user"
48
+ :owner="order.creator"
49
+ :creator="order.creator"
50
+ :date="order.createdAt"
51
+ />
52
+ <div class="pd-small">
35
53
  <p
36
54
  class="w-100 mn-b-thin p-big"
37
55
  >
38
56
  Order No.: #{{order._id}}
39
57
  </p>
40
58
 
59
+ <span class="mn-b-thin pd-r-thin pd-l-thin pd-b-nano pd-t-nano bg-second radius-extra t-white t-medium d-block w-max uppercase">
60
+ {{order.status}}
61
+ </span>
41
62
  <p
42
63
  class="mn-b-small t-transp w-100"
43
64
  >
@@ -49,23 +70,9 @@
49
70
  class="mn-b-small"
50
71
  >
51
72
 
52
- Order Created: {{formatDate(order.createdAt)}}
53
-
54
- <router-link
55
- :to="{
56
- name: 'AdminOrderEdit',
57
- params: {
58
- order: order._id
59
-
60
- }
61
- }"
62
- class="i-small"
63
- >
64
- EDIT
65
- </router-link>
66
73
  </p>
67
-
68
- </div>
74
+ </div>
75
+ </router-link>
69
76
  </section>
70
77
  </template>
71
78
 
@@ -76,8 +83,10 @@
76
83
  import Tab from '@pf/src/components/Tab/Tab.vue'
77
84
 
78
85
  import * as orders from '@pf/src/modules/orders/store/orders';
86
+ import * as auth from '@pf/src/modules/auth/store/auth';
79
87
 
80
88
  import CardOrder from '@pf/src/modules/orders/components/blocks/CardOrder.vue'
89
+ import CardHeader from '@pf/src/modules/globals/components/blocks/CardHeader.vue'
81
90
 
82
91
  const route = useRoute();
83
92
  const router = useRouter();
@@ -64,7 +64,7 @@ const controllerFactory = (db) => {
64
64
  req.query
65
65
  ),
66
66
  // For creator
67
- queryProcessorGlobals.getCreatorUserLookupStage(),
67
+ queryProcessorGlobals.getCreatorUserLookupStage(),
68
68
  queryProcessorGlobals.getCreatorOrganizationLookupStage(),
69
69
  // For owner
70
70
  queryProcessorGlobals.getOwnerUserLookupStage(),
@@ -4,6 +4,15 @@ module.exports = (db) => {
4
4
 
5
5
  const OrderSchema = new db.mongoose.Schema({
6
6
  client: {
7
+ type: {
8
+ type: String,
9
+ trim: true
10
+ },
11
+ target: {
12
+ type: db.mongoose.Schema.Types.ObjectId,
13
+ refPath: 'client.type',
14
+ },
15
+ table: { type: String, trim: true },
7
16
  name: { type: String, trim: true },
8
17
  phone: { type: Object, trim: true },
9
18
  email: { type: String, trim: true },
@@ -72,7 +81,7 @@ module.exports = (db) => {
72
81
  }
73
82
  });
74
83
 
75
- // applyOwnershipSchema(OrderSchema,db);
84
+ applyOwnershipSchema(OrderSchema,db);
76
85
 
77
86
  const Order = db.mongoose.model("Order", OrderSchema);
78
87
 
@@ -50,13 +50,8 @@ const state = reactive({
50
50
  });
51
51
 
52
52
  const actions = {
53
- async create(positions, owner, creator) {
53
+ async create(order) {
54
54
  try {
55
- let order = {
56
- positions: positions,
57
- owner: owner,
58
- creator: creator
59
- }
60
55
  const response = await $axios.post('/api/orders/create', order);
61
56
 
62
57
  state.all.push(response.data);
@@ -19,7 +19,7 @@
19
19
  <Field
20
20
  v-model:field="productQuantity"
21
21
  type="number"
22
- label="Quantity"
22
+ label="Qty"
23
23
  class="bg-white pd-small radius-small"
24
24
  >
25
25
  <Select
@@ -111,9 +111,9 @@
111
111
  const productNew = ref(null);
112
112
 
113
113
  const totalPrice = computed(() => {
114
- return leftovers.state.current.positions.reduce((sum, position) => {
114
+ return Number(leftovers.state.current.positions.reduce((sum, position) => {
115
115
  return sum + position.price;
116
- }, 0);
116
+ }, 0));
117
117
  });
118
118
 
119
119
  onMounted(async () => {