Compare commits

..

2 commits

Author SHA1 Message Date
nquidox
7aa2ff1d3a refresh on delete
All checks were successful
/ Make image (push) Successful in 44s
2025-11-02 23:46:22 +03:00
nquidox
cffc6acc2b zero prices block added
Some checks failed
/ Make image (push) Has been cancelled
2025-11-02 23:40:44 +03:00
9 changed files with 200 additions and 9 deletions

27
src/api/zeroPrices.js Normal file
View file

@ -0,0 +1,27 @@
import { apiClient } from '@/services/apiClient.js'
export const useZeroPrices = () => {
const getZeroPrices = async () => {
try {
return await apiClient.get('/merch/zeroprices')
} catch (error) {
console.log('Get zero prices error: ', error)
throw error
}
}
const deleteZeroPrices = async (list) => {
try {
await apiClient.delete('/merch/zeroprices', list)
}
catch (error) {
console.log('Delete zero prices error: ', error)
throw error
}
}
return {
getZeroPrices,
deleteZeroPrices,
}
}

View file

@ -17,6 +17,7 @@ const mainMenu = computed(() => {
{ label: 'Collection', key: 'collection' },
{ label: 'Charts', key: 'charts' },
{ label: 'Parsers', key: 'parsers' },
{ label: 'Zero prices', key: 'zeroprices' },
]
})

View file

@ -8,6 +8,7 @@ import PersonalView from '@/views/PersonalView.vue'
import AddMerchView from '@/views/AddMerchView.vue'
import DetailsView from '@/views/DetailsView.vue'
import LabelsView from '@/views/LabelsView.vue'
import ZeroPricesView from '@/views/ZeroPricesView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@ -58,6 +59,11 @@ const router = createRouter({
name: 'labels',
component: LabelsView,
},
{
path: '/zeroprices',
name: 'zeroprices',
component: ZeroPricesView,
},
],
})

View file

@ -138,12 +138,14 @@ export const apiClient = {
return request(url, {
method: 'POST',
body: isFormData ? data : JSON.stringify(data),
// headers: isFormData ? {} : { 'Content-Type': 'application/json' }
})
},
put: (url, data) => request(url, {
method: 'PUT',
body: JSON.stringify(data),
}),
delete: (url) => request(url, { method: 'DELETE' }),
delete: (url, data) => request(url, {
method: 'DELETE',
body: data ? JSON.stringify(data) : undefined,
}),
}

View file

@ -197,3 +197,8 @@ body,
justify-content: center;
margin-bottom: 20px;
}
.padding-lr-30 {
padding-left: 30px;
padding-right: 30px;
}

View file

@ -1,5 +1,5 @@
<script setup>
import { computed, ref, watch } from 'vue'
import { computed } from 'vue'
import router from '@/router/index.js'
import { useLabelsStore } from '@/stores/labelsStore.js'
@ -21,14 +21,13 @@ const addMerch = () => {
router.push({ name: 'addMerch' })
}
const localSearch = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
},
})
const selectedLabelUuids = computed({
@ -37,7 +36,7 @@ const selectedLabelUuids = computed({
},
set(value) {
emit('update:labelUuids', value)
}
},
})
const labelOptions = computed(() => {
@ -69,6 +68,4 @@ const labelOptions = computed(() => {
</div>
</template>
<style scoped>
</style>
<style scoped></style>

View file

@ -0,0 +1,54 @@
<script setup>
import { onMounted, ref } from 'vue'
import { useZeroPrices } from '@/api/zeroPrices.js'
import ZeroPriceCard from '@/views/ZeroPricesView/ZeroPriceCard.vue'
import ZeroPricesToolbar from '@/views/ZeroPricesView/ZeroPricesToolbar.vue'
const { getZeroPrices } = useZeroPrices()
const zeroPrices = ref([])
const toDelete = ref([])
const handleToggle = ({ id, merch_uuid, checked }) => {
if (checked) {
toDelete.value.push({ id, merch_uuid });
} else {
toDelete.value = toDelete.value.filter(item => item.id !== id);
}
}
const fetchZeroPrices = async () => {
try {
const response = await getZeroPrices()
zeroPrices.value = response.data
} catch (error) {
console.error(error)
}
}
const handleDeleted = () => {
toDelete.value = []
fetchZeroPrices()
}
onMounted(() => {
fetchZeroPrices()
})
</script>
<template>
<div v-if="zeroPrices.length === 0">
<n-h2 class="text-center">Zero prices</n-h2>
<n-h3 class="text-center">No data</n-h3>
</div>
<div v-else>
<div class="sticky-search-container">
<ZeroPricesToolbar :selected="toDelete" @deleted="handleDeleted" />
</div>
<div v-for="item in zeroPrices" :key="item.created_at">
<ZeroPriceCard :zero-price="item" @toggle="handleToggle" />
</div>
</div>
</template>
<style scoped></style>

View file

@ -0,0 +1,51 @@
<script setup>
import { ref } from 'vue'
const props = defineProps({
zeroPrice: {
type: Object,
required: true,
},
})
const isChecked = ref(false)
const emit = defineEmits(['toggle'])
const handleCheckboxChange = () => {
isChecked.value = !isChecked.value
emit('toggle', {
id: props.zeroPrice.id,
merch_uuid: props.zeroPrice.merch_uuid,
checked: isChecked.value,
})
}
</script>
<template>
<div class="zeroPriceCard mt-10">
<n-grid responsive="screen" item-responsive cols="4" :x-gap="16" :y-gap="16" class="shift">
<n-gi>
<n-checkbox :checked="isChecked" @update:checked="handleCheckboxChange">
<strong>Delete</strong>
</n-checkbox>
</n-gi>
<n-gi><strong>Name:</strong> {{ props.zeroPrice.name }}</n-gi>
<n-gi><strong>Created:</strong> {{ props.zeroPrice.created_at }}</n-gi>
<n-gi><strong>Origin:</strong> {{ props.zeroPrice.origin }}</n-gi>
</n-grid>
</div>
</template>
<style scoped>
.zeroPriceCard {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: #f5f5f5;
border-radius: 8px;
font-family: Arial, sans-serif;
font-size: 14px;
gap: 12px;
border: 1px solid #e0e0e0;
}
</style>

View file

@ -0,0 +1,48 @@
<script setup>
import { useMessage } from 'naive-ui'
import { useZeroPrices } from '@/api/zeroPrices.js'
const props = defineProps({
selected: {
type: Array,
required: true,
},
})
const messages = useMessage()
const { deleteZeroPrices } = useZeroPrices()
const emit = defineEmits(['deleted'])
const handleDelete = async () => {
try {
await deleteZeroPrices(props.selected)
messages.success("Selected zero prices deleted")
emit('deleted')
} catch (error) {
console.log(error)
messages.error("Error deleting selected prices")
}
}
</script>
<template>
<div class="toolbar button-container-evenly padding-lr-30">
<div v-if="props.selected.length === 0" class="toolbar-item">
<span>Select records to delete</span>
</div>
<div v-else class="toolbar-item">
{{ props.selected.length }} items selected
</div>
<div class="toolbar-item">
<n-button
type="error"
:disabled="props.selected.length === 0"
@click="handleDelete"
>
Delete Selected
</n-button>
</div>
</div>
</template>
<style scoped></style>