first commit

This commit is contained in:
2026-03-26 16:00:40 +03:00
parent 60d87dafcc
commit e6e62fa46b
13 changed files with 58 additions and 41 deletions

View File

@@ -1,5 +1,5 @@
import { $themeConfig } from '@/theme.config'
import { useAppStore } from '@/stores/app'
import { useAppStore, type LocaleCode } from '@/stores/app'
export default {
init() {
@@ -32,7 +32,7 @@ export default {
store.toggleSemidark(value === 'true' ? true : $themeConfig.semidark)
},
toggleLanguage(item?: { code: string; name: string }) {
toggleLanguage(item?: { code: LocaleCode; name: string }) {
const store = useAppStore()
const lang = item || store.languageList.find((entry) => entry.code === store.locale) || store.languageList[0]
store.toggleLocale(lang.code)

View File

@@ -490,6 +490,7 @@
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import type { ApexOptions } from 'apexcharts';
import apexchart from 'vue3-apexcharts';
import { useAppStore } from '@/stores/app';
import { useMeta } from '@/composables/use-meta';
@@ -546,7 +547,7 @@
},
responsive: [
{
breakPoint: 576,
breakpoint: 576,
options: {
chart: {
height: 95,
@@ -561,7 +562,7 @@
},
},
],
};
} as ApexOptions;
});
const bitcoinSeries = ref([
@@ -608,7 +609,7 @@
},
responsive: [
{
breakPoint: 576,
breakpoint: 576,
options: {
chart: {
height: 95,
@@ -623,7 +624,7 @@
},
},
],
};
} as ApexOptions;
});
const ethereumSeries = ref([
@@ -670,7 +671,7 @@
},
responsive: [
{
breakPoint: 576,
breakpoint: 576,
options: {
chart: {
height: 95,
@@ -685,7 +686,7 @@
},
},
],
};
} as ApexOptions;
});
const litecoinSeries = ref([
@@ -732,7 +733,7 @@
},
responsive: [
{
breakPoint: 576,
breakpoint: 576,
options: {
chart: {
height: 95,
@@ -747,7 +748,7 @@
},
},
],
};
} as ApexOptions;
});
const binanceSeries = ref([
@@ -794,7 +795,7 @@
},
responsive: [
{
breakPoint: 576,
breakpoint: 576,
options: {
chart: {
height: 95,
@@ -809,7 +810,7 @@
},
},
],
};
} as ApexOptions;
});
const tetherSeries = ref([
@@ -856,7 +857,7 @@
},
responsive: [
{
breakPoint: 576,
breakpoint: 576,
options: {
chart: {
height: 95,
@@ -871,7 +872,7 @@
},
},
],
};
} as ApexOptions;
});
const solanaSeries = ref([

View File

@@ -747,6 +747,7 @@
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import type { ApexOptions } from 'apexcharts';
import apexchart from 'vue3-apexcharts';
import { useAppStore } from '@/stores/app';
@@ -907,7 +908,7 @@
stops: isDark ? [100, 100] : [45, 100],
},
},
};
} as ApexOptions;
});
const revenueSeries = ref([
@@ -936,7 +937,7 @@
stroke: {
show: true,
width: 25,
colors: isDark ? '#0e1726' : '#fff',
colors: isDark ? ['#0e1726'] : ['#fff'],
},
colors: isDark ? ['#5c1ac3', '#e2a03f', '#e7515a', '#e2a03f'] : ['#e2a03f', '#5c1ac3', '#e7515a'],
legend: {
@@ -1002,7 +1003,7 @@
},
},
},
};
} as ApexOptions;
});
const salesByCategorySeries = ref([985, 737, 270]);
@@ -1076,7 +1077,7 @@
left: -20,
},
},
};
} as ApexOptions;
});
const dailySalesSeries = ref([
@@ -1137,7 +1138,7 @@
show: false,
},
},
};
} as ApexOptions;
});
const totalOrdersSeries = ref([

14
src/env.d.ts vendored
View File

@@ -4,4 +4,16 @@ declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
}
declare module 'vue-height-collapsible/vue3' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
declare module 'vue-height-collapsible/vue3/vue-height-collapsible.esm.js' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

View File

@@ -12,9 +12,9 @@ import type {
} from '@/types/product'
type QueryPrimitive = string | number | boolean | null | undefined
type QueryValue = QueryPrimitive | string[] | ProductAttributes | ProductAttributeAssignment[] | ProductMeta | Record<string, unknown>
export type QueryValue = QueryPrimitive | string[] | ProductAttributes | ProductAttributeAssignment[] | ProductMeta | Record<string, unknown>
export const buildQueryParams = (params: Record<string, QueryValue>) => {
export const buildQueryParams = (params: Record<string, unknown>) => {
const query: Record<string, string | number | boolean> = {}
Object.entries(params).forEach(([key, value]) => {
@@ -24,19 +24,19 @@ export const buildQueryParams = (params: Record<string, QueryValue>) => {
if (Array.isArray(value)) {
if (value.length > 0) {
query[key] = JSON.stringify(value)
query[key] = JSON.stringify(value as QueryValue)
}
return
}
if (typeof value === 'object') {
if (Object.keys(value).length > 0) {
query[key] = JSON.stringify(value)
query[key] = JSON.stringify(value as QueryValue)
}
return
}
query[key] = value
query[key] = value as string | number | boolean
})
return query

View File

@@ -47,7 +47,7 @@ class ApiService {
if (refreshToken) {
try {
const response = await this.refreshToken({ refreshToken })
const { accessToken, refreshToken: newRefreshToken } = response.data
const { accessToken, refreshToken: newRefreshToken } = response
localStorage.setItem('accessToken', accessToken)
localStorage.setItem('refreshToken', newRefreshToken)

View File

@@ -3,6 +3,7 @@ import i18n from '@/i18n'
import appSetting from '@/app-setting'
const rtlLanguages = new Set(['ae', 'fa', 'ar'])
export type LocaleCode = 'fa' | 'ae' | 'en'
export const useAppStore = defineStore('app', {
state: () => ({
@@ -13,13 +14,13 @@ export const useAppStore = defineStore('app', {
rtlClass: 'rtl',
animation: '',
navbar: 'navbar-sticky',
locale: 'fa',
locale: 'fa' as LocaleCode,
sidebar: false,
languageList: [
{ code: 'fa', name: 'فارسی' },
{ code: 'ae', name: 'Arabic' },
{ code: 'en', name: 'English' },
],
] as Array<{ code: LocaleCode; name: string }>,
isShowMainLoader: true,
semidark: false,
}),
@@ -81,7 +82,7 @@ export const useAppStore = defineStore('app', {
this.semidark = value
},
toggleLocale(payload: string | null = null) {
toggleLocale(payload: LocaleCode | null = null) {
const value = payload || this.locale
i18n.global.locale.value = value
localStorage.setItem('i18n_locale', value)

View File

@@ -209,7 +209,7 @@ export interface ProductFormPayload {
brandId?: string
brand: string
basePriceUSD: number
salePriceUSD?: number | null
salePriceUSD?: number | null | ''
stock: number
featured: boolean
type: ProductType

View File

@@ -139,8 +139,9 @@ export const normalizeAttributes = (attributes?: Record<string, unknown> | Produ
}, {})
}
export const attributesToEntries = (attributes?: ProductAttributes): AttributeEntry[] => {
const entries = Object.entries(attributes || {}).map(([key, value]) => ({
export const attributesToEntries = (attributes?: ProductAttributes | ProductAttributeAssignment[]): AttributeEntry[] => {
const normalizedAttributes = normalizeAttributes(attributes)
const entries = Object.entries(normalizedAttributes).map(([key, value]) => ({
key,
value: value === null || value === undefined ? '' : String(value),
}))
@@ -263,7 +264,7 @@ export const normalizeEnglishSlug = (value: string) =>
export const generateEnglishSlug = (value: string) => normalizeEnglishSlug(transliteratePersianToLatin(value))
export const formatCurrency = (value?: number | null) => {
export const formatCurrency = (value?: number | null | '') => {
const safeValue = Number(value || 0)
return new Intl.NumberFormat('en-US', {
style: 'currency',

View File

@@ -202,6 +202,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { ApexOptions } from 'apexcharts'
import apexchart from 'vue3-apexcharts'
import { useAppStore } from '@/stores/app'
import IconHorizontalDots from '@/components/icon/icon-horizontal-dots.vue'
@@ -399,7 +400,7 @@ const revenueChart = computed(() => {
stops: [40, 100],
},
},
}
} as ApexOptions
})
const salesByCategory = computed(() => {
@@ -446,7 +447,7 @@ const salesByCategory = computed(() => {
hover: { filter: { type: 'none', value: 0.15 } },
active: { filter: { type: 'none', value: 0.15 } },
},
}
} as ApexOptions
})
const dailySales = computed(() => ({
@@ -478,7 +479,7 @@ const dailySales = computed(() => ({
formatter: (value: number) => `${value} سفارش`,
},
},
}))
} as ApexOptions))
const inventoryChart = computed(() => ({
chart: {
@@ -510,5 +511,5 @@ const inventoryChart = computed(() => ({
formatter: (value: number) => `${value} SKU`,
},
},
}))
} as ApexOptions))
</script>

View File

@@ -169,7 +169,7 @@
v-model="form.slug"
type="text"
dir="ltr"
inputmode="latin"
inputmode="text"
class="form-input"
placeholder="skf"
@input="sanitizeSlugInput"

View File

@@ -224,7 +224,7 @@
v-model="form.slug"
type="text"
dir="ltr"
inputmode="latin"
inputmode="text"
class="form-input"
placeholder="bolbering-sanati"
@input="sanitizeSlugInput"

View File

@@ -127,7 +127,7 @@ const errors = reactive({
const errorMessage = ref('')
const countdown = ref(120) // 2 minutes
const isResending = ref(false)
let countdownInterval: NodeJS.Timeout | null = null
let countdownInterval: ReturnType<typeof setInterval> | null = null
const phone = ref(sessionStorage.getItem('otpPhone') || '')
const fullName = ref(sessionStorage.getItem('otpFullName') || '')
@@ -271,4 +271,4 @@ onUnmounted(() => {
clearInterval(countdownInterval)
}
})
</script>
</script>