Skip to content

Commit

Permalink
Merge pull request #51 from doroudi:doroudi/issue49
Browse files Browse the repository at this point in the history
feat: ✨ implement rates page
  • Loading branch information
doroudi authored Jan 19, 2024
2 parents a2b38ae + 2bcd4fc commit 3a503c6
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 12 deletions.
3 changes: 3 additions & 0 deletions src/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ declare global {
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useReviewStore: typeof import('./store/review')['useReviewStore']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
Expand Down Expand Up @@ -560,6 +561,7 @@ declare module 'vue' {
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
readonly useReviewStore: UnwrapRef<typeof import('./store/review.store')['useReviewStore']>
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
Expand Down Expand Up @@ -870,6 +872,7 @@ declare module '@vue/runtime-core' {
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
readonly useReviewStore: UnwrapRef<typeof import('./store/review.store')['useReviewStore']>
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
Expand Down
13 changes: 1 addition & 12 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,21 @@ 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']
NLayoutContent: typeof import('naive-ui')['NLayoutContent']
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']
ProductsManagement: typeof import('./components/Products/ProductsManagement.vue')['default']
ReviewManagement: typeof import('./components/Review/ReviewManagement.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Sidebar: typeof import('./components/Sidebar.vue')['default']
Expand Down
144 changes: 144 additions & 0 deletions src/components/Review/ReviewManagement.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<script setup lang='ts'>
import { getCurrentInstance } from 'vue'
import { type DataTableColumns, NButton, NIcon, NRate, NSpace, NText } from 'naive-ui/es/components'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
import {
Delete24Regular as DeleteIcon,
} from '@vicons/fluent'
import { storeToRefs } from 'pinia'
import { useDialog, useMessage } from 'naive-ui'
const { t } = useI18n()

Check warning on line 11 in src/components/Review/ReviewManagement.vue

View workflow job for this annotation

GitHub Actions / lint

't' is assigned a value but never used. Allowed unused vars must match /^_/u

Check failure on line 11 in src/components/Review/ReviewManagement.vue

View workflow job for this annotation

GitHub Actions / typecheck

't' is declared but its value is never read.
const store = useReviewStore()
const { reviews, isLoading } = storeToRefs(store)
const dialog = useDialog()
const message = useMessage()
const { proxy } = getCurrentInstance()

Check failure on line 17 in src/components/Review/ReviewManagement.vue

View workflow job for this annotation

GitHub Actions / typecheck

Property 'proxy' does not exist on type 'ComponentInternalInstance | null'.
onMounted(getItems)
const columns: DataTableColumns<RowData> = [
{
title: 'RATE',
key: 'rate',
render(row) {
return [
h(NRate, { color: 'gold', readonly: true, defaultValue: row.rate, allowHalf: true }),
]
},
},
{
title: 'COMMENT',
key: 'comment',
render(row) {
return h(NText,
{}, {
default: () => row.comment.message,
})
},
},
{
title: 'PRODUCT',
key: 'name',
render: row =>
h(NSpace, {}, {
default: () => [
h(NText, {}, { default: () => `${row.product.name}` }),
],
}),
},
{
title: 'CUSTOMER',
key: 'phone',
render(row) {
return [
h(NText, {}, { default: () => `${row.customer.firstName} ${row.customer.lastName}` }),
]
},
},
{
title: 'DATE',
key: 'date',
render(row) {
return h(NText,
{}, {
default: () => proxy.$filters.friendlyTime(row.date),
})
},
},
{
title: 'Actions',
key: 'actions',
width: 110,
render(row) {
return [
h(
NButton,
{
size: 'medium',
quaternary: true,
circle: true,
renderIcon: renderIcon(DeleteIcon),
onClick: () => handleDeleteItem(row),
},
),
]
},
},
]
const { options } = storeToRefs(store)
function renderIcon(icon: any) {
return () => h(NIcon, null, { default: () => h(icon) })
}
function handleDeleteItem(row: RowData) {
dialog.error({
title: 'Confirm',
content: 'Are you sure?',
positiveText: 'Yes, Delete',
negativeText: 'Cancel',
onPositiveClick: () => {
store.deleteProduct(row.id)
message.success('Product was deleted!')
},
})
}
function rowKey(row: RowData) {
return row.id
}
function getItems() {
store.getReviews(options.value)
}
function handlePageChange(page: number) {
options.value.page = page
getItems()
}
function handleSorterChange() {
getItems()
}
function handleFiltersChange() {
getItems()
}
</script>

<template>
<n-layout>
<n-layout-content>
<div class="px-3">
<n-data-table
remote :columns="columns" :data="reviews" :loading="isLoading" :pagination="options"
selectable :row-key="rowKey" @update:sorter="handleSorterChange" @update:filters="handleFiltersChange"
@update:page="handlePageChange"
/>
</div>
</n-layout-content>
</n-layout>
</template>

<style scoped lang='scss'></style>
42 changes: 42 additions & 0 deletions src/mocks/handlers/review.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { HttpResponse, http } from 'msw'
import { faker } from '@faker-js/faker'
import _ from 'lodash'
import { CreatePagedResponse } from '../handlers.utility'
import type { Review } from '~/models/Review'

const reviews = _.times(65, createFakeReview)
const handlers = [
http.get('/api/review/', ({ request }) => {
const response = CreatePagedResponse<Review>(request, reviews)
return HttpResponse.json(response, { status: 200 })
}),
]

function createFakeReview(): Review {
return {
id: faker.number.int().toString(),
date: faker.date.past(),
rate: faker.number.float({ max: 5 }),
product: {
name: faker.commerce.productName(),
id: faker.number.int().toString(),
},
comment: {
id: faker.number.int().toString(),
message: faker.commerce.productAdjective(),
},
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 }),
},
}
}

export default handlers
20 changes: 20 additions & 0 deletions src/models/Review.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Customer } from './Customer'

export interface Review {
id: string
customer: Customer
product: ReviewProduct
date: Date
rate: number
comment: Comment
}

export interface Comment {
id: string
message: string
}

export interface ReviewProduct {
id: string
name: string
}
14 changes: 14 additions & 0 deletions src/pages/Reviews/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
</script>

<route lang="yaml">
meta:
title: Reviews
</route>

<template>
<ReviewManagement />
</template>

<style scoped></style>
14 changes: 14 additions & 0 deletions src/services/review.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ApiService } from '~/common/api/api-service'
import type { PagedAndSortedRequest } from '~/models/PagedAndSortedRequest'
import type { PagedListResult } from '~/models/PagedListResult'
import type { Review } from '~/models/Review'

const apiService = new ApiService('review')
class ReviewService {
constructor() { }
async getReviewList(options: PagedAndSortedRequest): Promise<PagedListResult<Review>> {
const response = await apiService.getPagedList<Review>('', options)
return response
}
}
export default new ReviewService()
38 changes: 38 additions & 0 deletions src/store/review.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { acceptHMRUpdate, defineStore } from 'pinia'
import type { PagedAndSortedRequest } from '~/models/PagedAndSortedRequest'
import type { Review } from '~/models/Review'
import reviewService from '~/services/review.service'

export interface ReviewState {

}
export const useReviewStore = defineStore('Review', () => {
const reviews = ref<Review[]>([])

const reviewItem = ref<Review>()
const isLoading = ref(false)
const isSaving = ref(false)
const { options } = useOptions()

async function getReviews(options: PagedAndSortedRequest) {
isLoading.value = true
try {
const response = await reviewService.getReviewList(options)
reviews.value = response.items
options.pageSize = Math.trunc(response.totalCount / options.itemsPerPage)
}
finally {
isLoading.value = false
}
}
return {
reviews,
isSaving,
isLoading,
getReviews,
reviewItem,
options,
}
})
if (import.meta.hot)
import.meta.hot.accept(acceptHMRUpdate(useReviewStore, import.meta.hot))

0 comments on commit 3a503c6

Please sign in to comment.