From 8bccec63dbb46e3a5dcbad838d1331c0f10195d6 Mon Sep 17 00:00:00 2001 From: Saeid Doroudi Date: Sat, 20 Jan 2024 10:26:44 +0330 Subject: [PATCH 1/4] feat: orders view implemented --- src/auto-imports.d.ts | 3 + src/components.d.ts | 5 +- src/components/Orders/OrderManagement.vue | 172 ++++++++++++++++++++++ src/mocks/handlers/order.handler.ts | 48 ++++++ src/models/Customer.ts | 14 ++ src/models/Order.ts | 23 +++ src/pages/Orders/index.vue | 14 ++ src/services/order.service.ts | 23 +++ src/store/order.store.ts | 30 ++++ 9 files changed, 328 insertions(+), 4 deletions(-) create mode 100644 src/components/Orders/OrderManagement.vue create mode 100644 src/mocks/handlers/order.handler.ts create mode 100644 src/models/Order.ts create mode 100644 src/pages/Orders/index.vue create mode 100644 src/services/order.service.ts create mode 100644 src/store/order.store.ts diff --git a/src/auto-imports.d.ts b/src/auto-imports.d.ts index 03da606..65df1b1 100644 --- a/src/auto-imports.d.ts +++ b/src/auto-imports.d.ts @@ -224,6 +224,7 @@ declare global { const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination'] const useOnline: typeof import('@vueuse/core')['useOnline'] const useOptions: typeof import('./composables/options')['useOptions'] + const useOrderStore: typeof import('./store/order')['useOrderStore'] const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] const useParallax: typeof import('@vueuse/core')['useParallax'] const useParentElement: typeof import('@vueuse/core')['useParentElement'] @@ -541,6 +542,7 @@ declare module 'vue' { readonly useOffsetPagination: UnwrapRef readonly useOnline: UnwrapRef readonly useOptions: UnwrapRef + readonly useOrderStore: UnwrapRef readonly usePageLeave: UnwrapRef readonly useParallax: UnwrapRef readonly useParentElement: UnwrapRef @@ -851,6 +853,7 @@ declare module '@vue/runtime-core' { readonly useOffsetPagination: UnwrapRef readonly useOnline: UnwrapRef readonly useOptions: UnwrapRef + readonly useOrderStore: UnwrapRef readonly usePageLeave: UnwrapRef readonly useParallax: UnwrapRef readonly useParentElement: UnwrapRef diff --git a/src/components.d.ts b/src/components.d.ts index a31b312..a58cc11 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -26,13 +26,11 @@ declare module 'vue' { Navbar: typeof import('./components/Navbar.vue')['default'] NBadge: typeof import('naive-ui')['NBadge'] NButton: typeof import('naive-ui')['NButton'] - NCard: typeof import('naive-ui')['NCard'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NDataTable: typeof import('naive-ui')['NDataTable'] NDialogProvider: typeof import('naive-ui')['NDialogProvider'] NDrawer: typeof import('naive-ui')['NDrawer'] NDrawerContent: typeof import('naive-ui')['NDrawerContent'] - NDynamicTags: typeof import('naive-ui')['NDynamicTags'] NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] NIcon: typeof import('naive-ui')['NIcon'] @@ -46,11 +44,10 @@ declare module 'vue' { NNotificationProvider: typeof import('naive-ui')['NNotificationProvider'] NPageHeader: typeof import('naive-ui')['NPageHeader'] NPopselect: typeof import('naive-ui')['NPopselect'] - NSelect: typeof import('naive-ui')['NSelect'] NSpace: typeof import('naive-ui')['NSpace'] - NSwitch: typeof import('naive-ui')['NSwitch'] NTreeSelect: typeof import('naive-ui')['NTreeSelect'] NUpload: typeof import('naive-ui')['NUpload'] + OrderManagement: typeof import('./components/Orders/OrderManagement.vue')['default'] ProductsManagement: typeof import('./components/Products/ProductsManagement.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/src/components/Orders/OrderManagement.vue b/src/components/Orders/OrderManagement.vue new file mode 100644 index 0000000..4ffa63c --- /dev/null +++ b/src/components/Orders/OrderManagement.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/src/mocks/handlers/order.handler.ts b/src/mocks/handlers/order.handler.ts new file mode 100644 index 0000000..22604d2 --- /dev/null +++ b/src/mocks/handlers/order.handler.ts @@ -0,0 +1,48 @@ +import { HttpResponse, http } from 'msw' +import _ from 'lodash' +import { faker } from '@faker-js/faker' +import { CreatePagedResponse } from '../handlers.utility' +import { OrderStatus } from '~/models/Order' +import type { Order, OrderItem } from '~/models/Order' + +const orders = _.times(100, createFakeOrder) +const handlers = [ + http.get('/api/order/:id', ({ request }) => { + const response = CreatePagedResponse(request, orders) + return HttpResponse.json(response, { status: 200 }) + }), +] + +function createFakeOrder(): Order { + return { + id: faker.number.int().toString(), + status: faker.helpers.enumValue(OrderStatus), + items: _.times(4, createFakeOrderItems), + address: { + city: { name: 'Tehran', provinceId: faker.number.int().toString(), id: faker.number.int().toString() }, + province: { name: 'Tehran', id: faker.number.int().toString() }, + id: faker.number.int().toString(), + text: '30, Shams Ave, Ghasrodasht St', + }, + createdDate: faker.date.past(), + customer: { + id: faker.number.int().toString(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + address: [], + mobile: faker.phone.number(), + joinDate: faker.date.past(), + birthDate: faker.date.birthdate(), + email: faker.internet.email(), + ordersCount: faker.number.int({ max: 50 }), + }, + totalPrice: faker.number.int({ min: 20000, max: 10000000 }), + } +} + +function createFakeOrderItems(): OrderItem { + return { + + } +} +export default handlers diff --git a/src/models/Customer.ts b/src/models/Customer.ts index 0da5af9..997b278 100644 --- a/src/models/Customer.ts +++ b/src/models/Customer.ts @@ -11,7 +11,21 @@ export interface Customer { } export interface Address { + id: string + province: Province + city: City + text: string +} + +export interface City { + id: string + provinceId: string + name: string +} +export interface Province { + id: string + name: string } export interface CustomerCreateModel extends Customer { diff --git a/src/models/Order.ts b/src/models/Order.ts new file mode 100644 index 0000000..44bef2e --- /dev/null +++ b/src/models/Order.ts @@ -0,0 +1,23 @@ +import type { Address, Customer } from './Customer' + +export interface Order { + id: string + customer: Customer + items: OrderItem[] + address: Address + status: OrderStatus + createdDate: Date + totalPrice: number +} + +export interface OrderItem { + id: string +} + +export enum OrderStatus { + Submitted, + Processing, + ReadyToSend, + Sent, + Delivered, +} diff --git a/src/pages/Orders/index.vue b/src/pages/Orders/index.vue new file mode 100644 index 0000000..954fe21 --- /dev/null +++ b/src/pages/Orders/index.vue @@ -0,0 +1,14 @@ + + + +meta: + title: Orders + + + + + diff --git a/src/services/order.service.ts b/src/services/order.service.ts new file mode 100644 index 0000000..362ea3e --- /dev/null +++ b/src/services/order.service.ts @@ -0,0 +1,23 @@ +import { ApiService } from '~/common/api/api-service' +import type { Order } from '~/models/Order' +import type { PagedAndSortedRequest } from '~/models/PagedAndSortedRequest' +import type { PagedListResult } from '~/models/PagedListResult' + +const apiService = new ApiService('Order') +class OrderService { + constructor() { } + async getOrderList(options: PagedAndSortedRequest): Promise> { + const response = await apiService.getPagedList('', options) + return response + } + + async getOrder(id: string): Promise { + const response = await apiService.get(id) + return response + } + + async deleteOrder(id: string): Promise { + return await apiService.delete(id) + } +} +export default new OrderService() diff --git a/src/store/order.store.ts b/src/store/order.store.ts new file mode 100644 index 0000000..d814c3f --- /dev/null +++ b/src/store/order.store.ts @@ -0,0 +1,30 @@ +import { acceptHMRUpdate, defineStore } from 'pinia' +import type { Order } from '~/models/Order' +import type { PagedAndSortedRequest } from '~/models/PagedAndSortedRequest' +import orderService from '~/services/order.service' + +export const useOrderStore = defineStore('Order', () => { + const orders = ref([]) + const isLoading = ref(false) + const isSaving = ref(false) + const { options } = useOptions() + + async function getOrders(options: PagedAndSortedRequest) { + isLoading.value = true + try { + const response = await orderService.getOrderList(options) + orders.value = response.items + options.pageSize = Math.trunc(response.totalCount / options.itemsPerPage) + } + finally { + isLoading.value = false + } + } + + return { + orders, + getOrders, + } +}) +if (import.meta.hot) + import.meta.hot.accept(acceptHMRUpdate(useOrderStore, import.meta.hot)) From 2609ee01564fdd01a1a68bea72a988ef72e59472 Mon Sep 17 00:00:00 2001 From: Saeid Doroudi Date: Sat, 20 Jan 2024 12:28:46 +0330 Subject: [PATCH 2/4] feat: :sparkles: implement orders list orders management view implemented, get list of orders, show state and api handlers Fixes #48 --- src/components.d.ts | 13 ++++++ src/components/Orders/OrderManagement.vue | 40 ++++++++----------- .../Products/ProductsManagement.vue | 13 +----- src/components/Sidebar.vue | 8 +++- src/main.ts | 4 +- src/mocks/handlers/order.handler.ts | 23 ++++------- src/models/Order.ts | 11 +++++ src/services/order.service.ts | 8 ++-- src/store/order.store.ts | 11 ++++- 9 files changed, 70 insertions(+), 61 deletions(-) diff --git a/src/components.d.ts b/src/components.d.ts index 1840dcb..94eb764 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -26,9 +26,15 @@ declare module 'vue' { Navbar: typeof import('./components/Navbar.vue')['default'] NBadge: typeof import('naive-ui')['NBadge'] NButton: typeof import('naive-ui')['NButton'] + NCard: typeof import('naive-ui')['NCard'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NDataTable: typeof import('naive-ui')['NDataTable'] NDialogProvider: typeof import('naive-ui')['NDialogProvider'] + NDrawer: typeof import('naive-ui')['NDrawer'] + NDrawerContent: typeof import('naive-ui')['NDrawerContent'] + NDynamicTags: typeof import('naive-ui')['NDynamicTags'] + NForm: typeof import('naive-ui')['NForm'] + NFormItem: typeof import('naive-ui')['NFormItem'] NIcon: typeof import('naive-ui')['NIcon'] NInput: typeof import('naive-ui')['NInput'] NLayout: typeof import('naive-ui')['NLayout'] @@ -36,9 +42,16 @@ declare module 'vue' { NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NMenu: typeof import('naive-ui')['NMenu'] NMessageProvider: typeof import('naive-ui')['NMessageProvider'] + NModal: typeof import('naive-ui')['NModal'] NNotificationProvider: typeof import('naive-ui')['NNotificationProvider'] NPageHeader: typeof import('naive-ui')['NPageHeader'] NPopselect: typeof import('naive-ui')['NPopselect'] + NSelect: typeof import('naive-ui')['NSelect'] + NSpace: typeof import('naive-ui')['NSpace'] + NSwitch: typeof import('naive-ui')['NSwitch'] + NTreeSelect: typeof import('naive-ui')['NTreeSelect'] + NUpload: typeof import('naive-ui')['NUpload'] + OrderManagement: typeof import('./components/Orders/OrderManagement.vue')['default'] ProductsManagement: typeof import('./components/Products/ProductsManagement.vue')['default'] ReviewManagement: typeof import('./components/Review/ReviewManagement.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] diff --git a/src/components/Orders/OrderManagement.vue b/src/components/Orders/OrderManagement.vue index 4ffa63c..7096125 100644 --- a/src/components/Orders/OrderManagement.vue +++ b/src/components/Orders/OrderManagement.vue @@ -2,8 +2,8 @@ import { type DataTableColumns, NButton, NIcon, NSpace, NTag, NText } from 'naive-ui/es/components' import type { RowData } from 'naive-ui/es/data-table/src/interface' import { + Open24Regular as ArrowIcon, Delete24Regular as DeleteIcon, - Edit24Regular as EditIcon, Add24Filled as PlusIcon, } from '@vicons/fluent' import { storeToRefs } from 'pinia' @@ -16,33 +16,26 @@ const { orders, isLoading } = storeToRefs(store) const dialog = useDialog() const message = useMessage() const router = useRouter() +const { proxy } = getCurrentInstance() onMounted(getItems) const columns: DataTableColumns = [ { - type: 'selection', - }, - { - title: 'CUSTOMER', - key: 'name', - render: row => - h(NSpace, {}, { - default: () => [ - h(NText, {}, { default: () => row.customer.firstName }), - ], - }), + title: 'Customer', + key: 'customer', + }, { - title: 'DATE', - key: 'creationDate', - render: row => h(NText, {}, { default: () => $filters.friendlyTime(row.creationDate) }), + title: 'Date', + key: 'createdDate', + render: row => h(NText, {}, { default: () => proxy.$filters.friendlyTime(row.createdDate) }), }, { - title: 'ITEMS COUNT', + title: 'Items Count', key: 'itemsCount', }, { - title: 'PRICE', + title: 'Price', key: 'category', render(row) { return h(NText, @@ -52,7 +45,7 @@ const columns: DataTableColumns = [ }, }, { - title: 'STATUS', + title: 'Status', key: 'status', render: row => h(NTag, { type: getStatusColor(row.status) }, @@ -68,11 +61,10 @@ const columns: DataTableColumns = [ NButton, { size: 'medium', - renderIcon: renderIcon(EditIcon), quaternary: true, circle: true, - class: 'mr-2', - onClick: () => { }, + renderIcon: renderIcon(ArrowIcon), + onClick: () => {}, }, ), h( @@ -127,7 +119,7 @@ function rowKey(row: RowData) { return row.id } function getItems() { - store.getProducts(options.value) + store.getOrders(options.value) } function handlePageChange(page: number) { @@ -160,8 +152,8 @@ function handleFiltersChange() { diff --git a/src/components/Products/ProductsManagement.vue b/src/components/Products/ProductsManagement.vue index e8da66a..f015080 100644 --- a/src/components/Products/ProductsManagement.vue +++ b/src/components/Products/ProductsManagement.vue @@ -3,7 +3,6 @@ import { type DataTableColumns, NButton, NIcon, NImage, NSpace, NSwitch, NTag, N import type { RowData } from 'naive-ui/es/data-table/src/interface' import { Delete24Regular as DeleteIcon, - Edit24Regular as EditIcon, Add24Filled as PlusIcon, Star20Filled as StarIcon, } from '@vicons/fluent' @@ -76,17 +75,7 @@ const columns: DataTableColumns = [ width: 110, render(row) { return [ - h( - NButton, - { - size: 'medium', - renderIcon: renderIcon(EditIcon), - quaternary: true, - circle: true, - class: 'mr-2', - onClick: () => { }, - }, - ), + h( NButton, { diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 701f04e..0fa32cc 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -1,5 +1,5 @@