merge with front and apps verbose names update
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type OptionChildren = {
|
||||
id: number | string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type Option = {
|
||||
name: string;
|
||||
children: { name: string }[];
|
||||
children: OptionChildren[];
|
||||
};
|
||||
|
||||
type Props = {
|
||||
options: Option[];
|
||||
modelValue: string[];
|
||||
modelValue: number | string;
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
@@ -18,7 +23,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
placeholder: "جست و جو",
|
||||
});
|
||||
|
||||
const { modelValue } = toRefs(props);
|
||||
const { options, modelValue } = toRefs(props);
|
||||
|
||||
// emit
|
||||
|
||||
@@ -26,25 +31,29 @@ const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
// state
|
||||
|
||||
const value = ref<string[]>([]);
|
||||
const value = ref<OptionChildren>();
|
||||
|
||||
// watch
|
||||
|
||||
watch(
|
||||
() => value.value,
|
||||
(newValue) => {
|
||||
emit("update:modelValue", newValue);
|
||||
(newValue: OptionChildren) => {
|
||||
if (!!newValue) {
|
||||
emit("update:modelValue", newValue.id);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => modelValue.value,
|
||||
(newValue: string[]) => {
|
||||
value.value = newValue;
|
||||
(newValue) => {
|
||||
const target = options.value
|
||||
.flatMap((option) => option.children)
|
||||
.find((child) => child.id == newValue);
|
||||
|
||||
value.value = target || null;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -54,7 +63,8 @@ watch(
|
||||
class="w-full inline-flex items-center justify-between rounded-xl border-[1.5px] border-slate-200 focus:border-slate-800 px-[1rem] text-sm leading-none py-3.5 gap-[5px] bg-slate-50 text-black hover:border-black transition-all data-[placeholder]:text-black/80 typo-label-sm outline-none"
|
||||
>
|
||||
<ComboboxInput
|
||||
class="!bg-transparent outline-none text-black h-full selection:bg-slate-100 placeholder-slate-400"
|
||||
:display-value="(v) => (!!v ? v.name : '')"
|
||||
class="!bg-transparent outline-none text-black h-full w-full selection:bg-slate-100 placeholder-slate-400"
|
||||
:placeholder="placeholder"
|
||||
/>
|
||||
<ComboboxTrigger class="cursor-pointer">
|
||||
@@ -72,10 +82,7 @@ watch(
|
||||
|
||||
<template v-for="(group, index) in options" :key="group.name">
|
||||
<ComboboxGroup>
|
||||
<ComboboxSeparator
|
||||
v-if="index !== 0"
|
||||
class="h-6"
|
||||
/>
|
||||
<ComboboxSeparator v-if="index !== 0" class="h-6" />
|
||||
|
||||
<ComboboxLabel
|
||||
class="flex items-center justify-between px-[1.2rem] w-full text-md text-black font-bold bg-slate-200/50 leading-[25px] py-3 rounded-lg"
|
||||
@@ -83,13 +90,13 @@ watch(
|
||||
<span>
|
||||
{{ group.name }}
|
||||
</span>
|
||||
<Icon name="ci:delivery-boxes" size="18px"/>
|
||||
<Icon name="ci:delivery-boxes" size="18px" />
|
||||
</ComboboxLabel>
|
||||
|
||||
<ComboboxItem
|
||||
v-for="option in group.children"
|
||||
:key="option.name"
|
||||
:value="option.name"
|
||||
:value="option"
|
||||
class="text-sm cursor-pointer leading-none text-slate-700 my-1.5 rounded-md hover:bg-slate-200/25 flex items-center py-2.5 px-[1.2rem] relative select-none data-[disabled]:text-slate-50 data-[disabled]:pointer-events-none"
|
||||
>
|
||||
<ComboboxItemIndicator
|
||||
@@ -98,10 +105,10 @@ watch(
|
||||
<Icon name="ci:checkmark" size="18" />
|
||||
</ComboboxItemIndicator>
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon name="ci:minus" class="opacity-50"/>
|
||||
<Icon name="ci:minus" class="opacity-50" />
|
||||
<span>
|
||||
{{ option.name }}
|
||||
</span>
|
||||
{{ option.name }}
|
||||
</span>
|
||||
</div>
|
||||
</ComboboxItem>
|
||||
</ComboboxGroup>
|
||||
|
||||
@@ -17,10 +17,13 @@ const sort_filter = ref([
|
||||
{ title: "ارزان ترین ها", value: "-price" },
|
||||
]);
|
||||
|
||||
const sliderValue = ref([PRODUCT_RANGE.min, PRODUCT_RANGE.max]);
|
||||
const sliderValue = ref([
|
||||
params.price_gte ?? PRODUCT_RANGE.min,
|
||||
params.price_lte ?? PRODUCT_RANGE.max,
|
||||
]);
|
||||
|
||||
const has_discount = ref(JSON.parse(params.has_discount) ?? false);
|
||||
const in_stock = ref(JSON.parse(params.in_stock) ?? false);
|
||||
const has_discount = ref(JSON.parse(params.has_discount ?? false));
|
||||
const in_stock = ref(JSON.parse(params.in_stock ?? false));
|
||||
|
||||
const sliderValueDebounced = refDebounced(sliderValue, 1000);
|
||||
|
||||
@@ -55,6 +58,7 @@ const allCategories = computed(() => {
|
||||
name: category.name,
|
||||
children: category.subcategorys.map((sub) => {
|
||||
return {
|
||||
id: sub.id,
|
||||
name: sub.name,
|
||||
};
|
||||
}),
|
||||
@@ -66,11 +70,11 @@ const allCategories = computed(() => {
|
||||
|
||||
const resetFilters = () => {
|
||||
params.search = "";
|
||||
params.sort = "newest";
|
||||
params.sort = "";
|
||||
sliderValue.value = [PRODUCT_RANGE.min, PRODUCT_RANGE.max];
|
||||
has_discount.value = false;
|
||||
in_stock.value = false;
|
||||
params.category = "";
|
||||
params.category = undefined;
|
||||
};
|
||||
|
||||
// watch
|
||||
@@ -83,17 +87,6 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
watchOnce(
|
||||
() => [params.price_gte, params.price_lte],
|
||||
([newGte, newLte]) => {
|
||||
sliderValue.value[0] = newGte;
|
||||
sliderValue.value[1] = newLte;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => [has_discount.value, in_stock.value],
|
||||
([newHasDiscount, newInStock]) => {
|
||||
@@ -172,21 +165,13 @@ watch(
|
||||
<div class="flex-center gap-2">
|
||||
<span class="text-sm text-black">حداقل</span>
|
||||
<span class="text-sm text-black">
|
||||
{{
|
||||
"price_gte" in params
|
||||
? sliderValue[0].toLocaleString()
|
||||
: PRODUCT_RANGE.min
|
||||
}}
|
||||
{{ sliderValue[0].toLocaleString() }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-center gap-2">
|
||||
<span class="text-sm text-black">حداکثر</span>
|
||||
<span class="text-sm text-black">
|
||||
{{
|
||||
"price_lte" in params
|
||||
? sliderValue[1].toLocaleString()
|
||||
: PRODUCT_RANGE.max
|
||||
}}
|
||||
{{ sliderValue[1].toLocaleString() }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
|
||||
export type GetCategoriesResponse = Category[];
|
||||
|
||||
const useGetCategories = () => {
|
||||
|
||||
// state
|
||||
|
||||
const { $axios: axios } = useNuxtApp();
|
||||
@@ -16,13 +15,16 @@ const useGetCategories = () => {
|
||||
// methods
|
||||
|
||||
const handleGetCategories = async () => {
|
||||
const { data } = await axios.get<GetCategoriesResponse>(`${API_ENDPOINTS.products.categories}`);
|
||||
const { data } = await axios.get<GetCategoriesResponse>(
|
||||
`${API_ENDPOINTS.products.categories}`
|
||||
);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
return useQuery({
|
||||
queryKey: [QUERY_KEYS.categories],
|
||||
queryFn: () => handleGetCategories()
|
||||
queryFn: () => handleGetCategories(),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@ import { PRODUCT_RANGE } from "~/constants";
|
||||
|
||||
// state
|
||||
|
||||
const params: GetProductsFilters = useUrlSearchParams("history");
|
||||
const params: GetProductsFilters = useUrlSearchParams("history", {
|
||||
removeFalsyValues: true,
|
||||
removeNullishValues: true,
|
||||
});
|
||||
|
||||
const filters = computed(() => {
|
||||
return {
|
||||
@@ -87,14 +90,14 @@ watch(
|
||||
</div>
|
||||
</template>
|
||||
</Input>
|
||||
<!-- <Suspense>
|
||||
<Suspense>
|
||||
<FilterButton />
|
||||
<template #fallback>
|
||||
<Skeleton
|
||||
class="!w-[10.35rem] !h-[3.35rem] !rounded-full"
|
||||
/>
|
||||
</template>
|
||||
</Suspense> -->
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
|
||||
Reference in New Issue
Block a user