generated from antfu-collective/vitesse
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30 from doroudi/doroudi/issue27
- Loading branch information
Showing
14 changed files
with
459 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
<script setup lang='ts'> | ||
import { type DataTableColumns, NButton, NIcon } from 'naive-ui/es/components' | ||
import type { RowData } from 'naive-ui/es/data-table/src/interface' | ||
import { | ||
DismissCircle24Regular as DeleteIcon, | ||
Edit32Regular as EditIcon, | ||
AddCircle20Regular as PlusIcon, | ||
} from '@vicons/fluent' | ||
import { storeToRefs } from 'pinia' | ||
import { useDialog, useMessage } from 'naive-ui' | ||
const { t } = useI18n() | ||
const store = useBrandStore() | ||
const { brands, isLoading } = storeToRefs(store) | ||
const dialog = useDialog() | ||
const message = useMessage() | ||
onMounted(getItems) | ||
const columns: DataTableColumns<RowData> = [ | ||
{ | ||
title: 'Name', | ||
key: 'name', | ||
}, | ||
{ | ||
title: 'Url Slog', | ||
key: 'url', | ||
}, | ||
{ | ||
title: 'Actions', | ||
key: 'actions', | ||
width: 200, | ||
render(row) { | ||
return [ | ||
h( | ||
NButton, | ||
{ | ||
size: 'small', | ||
renderIcon: renderIcon(EditIcon), | ||
ghost: true, | ||
class: 'mr-2', | ||
onClick: () => edit(row), | ||
}, | ||
{ default: () => 'Edit' }, | ||
), | ||
h( | ||
NButton, | ||
{ | ||
size: 'small', | ||
type: 'error', | ||
ghost: true, | ||
renderIcon: renderIcon(DeleteIcon), | ||
onClick: () => handleDeleteItem(row), | ||
}, | ||
{ default: () => 'Delete' }, | ||
), | ||
] | ||
}, | ||
}, | ||
] | ||
const { options } = storeToRefs(store) | ||
const showAddDialog = ref(false) | ||
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.deleteBrand(row.id) | ||
message.success('Brand was deleted!') | ||
}, | ||
}) | ||
} | ||
function rowKey(row: RowData) { | ||
return row.id | ||
} | ||
function getItems() { | ||
store.getBrands(options.value) | ||
} | ||
function handlePageChange(page: number) { | ||
options.value.page = page | ||
getItems() | ||
} | ||
function handleFiltersChange() { | ||
getItems() | ||
} | ||
function createBrand() { | ||
showAddDialog.value = true | ||
} | ||
</script> | ||
|
||
<template> | ||
<n-layout> | ||
<n-layout-content> | ||
<div> | ||
<div class="flex items-center mb-5"> | ||
<h1 class="page-title mx-2"> | ||
{{ t('brands.title') }} | ||
</h1> | ||
<NButton type="primary" quaternary round @click="createBrand"> | ||
<template #icon> | ||
<NIcon> | ||
<PlusIcon /> | ||
</NIcon> | ||
</template> | ||
{{ t('brands.createButton') }} | ||
</NButton> | ||
</div> | ||
<n-data-table | ||
remote :columns="columns" :data="brands" :loading="isLoading" :pagination="options" | ||
:row-key="rowKey" @update:sorter="handleSorterChange" @update:filters="handleFiltersChange" | ||
@update:page="handlePageChange" | ||
/> | ||
</div> | ||
</n-layout-content> | ||
|
||
<n-drawer v-model:show="showAddDialog" :width="502" placement="right"> | ||
<n-drawer-content closable title="Create Brand"> | ||
<CreateBrand @close="showAddDialog = false" /> | ||
</n-drawer-content> | ||
</n-drawer> | ||
</n-layout> | ||
</template> | ||
|
||
<style scoped lang='scss'> | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<script setup lang='ts'> | ||
import type { FormInst, FormRules } from 'naive-ui/es/form' | ||
import { storeToRefs } from 'pinia' | ||
import type { CategoryCreateModel } from '~/models/Category' | ||
const emits = defineEmits(['close']) | ||
const brandStore = useBrandStore() | ||
const { isLoading } = storeToRefs(brandStore) | ||
const brandItem = ref<CategoryCreateModel>({ name: '', parentId: 0 }) | ||
const { t } = useI18n() | ||
const formRef = ref<FormInst | null>(null) | ||
async function create() { | ||
formRef.value?.validate(async (errors: any) => { | ||
if (!errors) { | ||
await brandStore.createBrand(brandItem.value) | ||
emits('close') | ||
} | ||
}) | ||
} | ||
const nameInput = ref() | ||
onMounted(() => { | ||
nameInput.value?.focus() | ||
}) | ||
const rules: FormRules = { | ||
name: [ | ||
{ | ||
required: true, | ||
trigger: ['blur', 'change'], | ||
message: t('brands.validations.name'), | ||
}, | ||
], | ||
url: [ | ||
{ | ||
required: true, | ||
trigger: ['blur', 'change'], | ||
message: t('brands.validations.url'), | ||
}, | ||
], | ||
image: [ | ||
{ | ||
required: true, | ||
trigger: ['blur', 'change'], | ||
message: t('brands.validations.image'), | ||
}, | ||
], | ||
} | ||
const showModalRef = ref(false) | ||
const previewImageUrlRef = ref('') | ||
function handlePreview(file: UploadFileInfo) { | ||
const { url } = file | ||
previewImageUrlRef.value = url as string | ||
showModalRef.value = true | ||
} | ||
</script> | ||
|
||
<template> | ||
<n-form ref="formRef" :model="brandItem" :rules="rules" @submit.prevent="create()"> | ||
<div class="form-control"> | ||
<n-form-item class="mb-5" path="name" :label="t('brands.create.brandName')"> | ||
<n-input | ||
id="name" ref="nameInput" v-model:value="brandItem.name" autofocus | ||
:placeholder="t('brands.create.brandName')" | ||
/> | ||
</n-form-item> | ||
</div> | ||
<div class="form-control flex flex-col mb-5"> | ||
<n-form-item path="url" :label="t('brands.create.url')"> | ||
<n-input | ||
v-model:value="brandItem.url" autofocus | ||
:placeholder="t('brands.create.url')" | ||
/> | ||
</n-form-item> | ||
</div> | ||
|
||
<div class="form-control"> | ||
<n-form-item class="mb-5" path="image" :label="t('brands.create.image')"> | ||
<n-upload | ||
:default-file-list="previewFileList" | ||
list-type="image-card" | ||
accept="image/png, image/jpeg" | ||
max="1" | ||
@preview="handlePreview" | ||
/> | ||
<n-modal | ||
v-model:show="showModal" | ||
preset="card" | ||
style="width: 600px" | ||
title="A Cool Picture" | ||
> | ||
<img :src="previewImageUrl" style="width: 100%"> | ||
</n-modal> | ||
</n-form-item> | ||
</div> | ||
<n-button attr-type="submit" size="large" :block="true" type="primary" :loading="isLoading"> | ||
{{ t('brands.create.buttonTitle') }} | ||
</n-button> | ||
</n-form> | ||
</template> | ||
|
||
<style scoped lang='scss'></style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { rest } from 'msw' | ||
import _ from 'lodash' | ||
import { faker } from '@faker-js/faker' | ||
import { CreatePagedResponse } from '../handlers.utility' | ||
import type { Brand, BrandCreateModel } from '~/models/Brand' | ||
|
||
const brands = _.times(7, createFakeBrand) | ||
const handlers = [ | ||
rest.get('/api/Brand', (req, res, ctx) => { | ||
const response = CreatePagedResponse<Brand>(req, brands) | ||
return res( | ||
ctx.status(200), | ||
ctx.delay(200), | ||
ctx.json(response), | ||
) | ||
}), | ||
rest.post('/api/brand', async (req, res, ctx) => { | ||
const newItem = await req.json<BrandCreateModel>() | ||
const brand: Brand = { | ||
id: faker.datatype.number({ max: 2000 }).toString(), | ||
name: newItem.name, | ||
url: newItem.url, | ||
image: newItem.image, | ||
} | ||
brands.push(brand) | ||
return res( | ||
ctx.status(200), | ||
ctx.delay(200), | ||
ctx.json(brand), | ||
) | ||
}), | ||
rest.delete('/api/Brand/:id', (req, res, ctx) => { | ||
const id = req.params.id.toString() | ||
const itemIndex = brands.findIndex(x => x.id === id) | ||
brands.splice(itemIndex, 1) | ||
return res( | ||
ctx.delay(1000), | ||
ctx.status(200), | ||
ctx.json(true), | ||
) | ||
}), | ||
|
||
] | ||
|
||
function createFakeBrand(): Brand { | ||
const name = faker.company.name() | ||
return { | ||
id: faker.datatype.number().toString(), | ||
name, | ||
image: '', | ||
url: toKebabCase(name), | ||
} | ||
} | ||
|
||
function toKebabCase(str: string) { | ||
return str.replaceAll(' ', '').replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() | ||
} | ||
|
||
export default handlers |
Oops, something went wrong.