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

View File

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

View File

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

12
src/env.d.ts vendored
View File

@@ -5,3 +5,15 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any> const component: DefineComponent<{}, {}, any>
export default component 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' } from '@/types/product'
type QueryPrimitive = string | number | boolean | null | undefined 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> = {} const query: Record<string, string | number | boolean> = {}
Object.entries(params).forEach(([key, value]) => { Object.entries(params).forEach(([key, value]) => {
@@ -24,19 +24,19 @@ export const buildQueryParams = (params: Record<string, QueryValue>) => {
if (Array.isArray(value)) { if (Array.isArray(value)) {
if (value.length > 0) { if (value.length > 0) {
query[key] = JSON.stringify(value) query[key] = JSON.stringify(value as QueryValue)
} }
return return
} }
if (typeof value === 'object') { if (typeof value === 'object') {
if (Object.keys(value).length > 0) { if (Object.keys(value).length > 0) {
query[key] = JSON.stringify(value) query[key] = JSON.stringify(value as QueryValue)
} }
return return
} }
query[key] = value query[key] = value as string | number | boolean
}) })
return query return query

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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