logo set
This commit is contained in:
@@ -61,3 +61,23 @@ export function deleteBusinessImage(businessId: string, imageId: string) {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
export function uploadBusinessLogoLight(businessId: string, file: File) {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
return apiFormData<Business>(`/businesses/${businessId}/logo-light`, form);
|
||||
}
|
||||
|
||||
export function uploadBusinessLogoDark(businessId: string, file: File) {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
return apiFormData<Business>(`/businesses/${businessId}/logo-dark`, form);
|
||||
}
|
||||
|
||||
export function removeBusinessLogoLight(businessId: string) {
|
||||
return api<Business>(`/businesses/${businessId}/logo-light`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
export function removeBusinessLogoDark(businessId: string) {
|
||||
return api<Business>(`/businesses/${businessId}/logo-dark`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
@@ -1,21 +1,43 @@
|
||||
import { api, apiFormData } from './client';
|
||||
|
||||
export type PlatformSettings = {
|
||||
loginHeroImageUrl: string | null;
|
||||
};
|
||||
|
||||
export function fetchPlatformSettings() {
|
||||
return api<PlatformSettings>('/platform-settings');
|
||||
}
|
||||
|
||||
export function uploadLoginHeroImage(file: File) {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
return apiFormData<PlatformSettings>('/platform-settings/login-hero-image', form);
|
||||
}
|
||||
|
||||
export function removeLoginHeroImage() {
|
||||
return api<PlatformSettings>('/platform-settings/login-hero-image', {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
import { api, apiFormData } from './client';␍
|
||||
␍
|
||||
export type PlatformSettings = {␍
|
||||
loginHeroImageUrl: string | null;␍
|
||||
logoLightUrl: string | null;␍
|
||||
logoDarkUrl: string | null;␍
|
||||
};␍
|
||||
␍
|
||||
export function fetchPlatformSettings() {␍
|
||||
return api<PlatformSettings>('/platform-settings');␍
|
||||
}␍
|
||||
␍
|
||||
export function uploadLoginHeroImage(file: File) {␍
|
||||
const form = new FormData();␍
|
||||
form.append('file', file);␍
|
||||
return apiFormData<PlatformSettings>('/platform-settings/login-hero-image', form);␍
|
||||
}␍
|
||||
␍
|
||||
export function removeLoginHeroImage() {␍
|
||||
return api<PlatformSettings>('/platform-settings/login-hero-image', {␍
|
||||
method: 'DELETE',␍
|
||||
});␍
|
||||
}␍
|
||||
␍
|
||||
export function uploadPlatformLogoLight(file: File) {␍
|
||||
const form = new FormData();␍
|
||||
form.append('file', file);␍
|
||||
return apiFormData<PlatformSettings>('/platform-settings/logo-light', form);␍
|
||||
}␍
|
||||
␍
|
||||
export function uploadPlatformLogoDark(file: File) {␍
|
||||
const form = new FormData();␍
|
||||
form.append('file', file);␍
|
||||
return apiFormData<PlatformSettings>('/platform-settings/logo-dark', form);␍
|
||||
}␍
|
||||
␍
|
||||
export function removePlatformLogoLight() {␍
|
||||
return api<PlatformSettings>('/platform-settings/logo-light', { method: 'DELETE' });␍
|
||||
}␍
|
||||
␍
|
||||
export function removePlatformLogoDark() {␍
|
||||
return api<PlatformSettings>('/platform-settings/logo-dark', { method: 'DELETE' });␍
|
||||
}␍
|
||||
|
||||
@@ -73,6 +73,8 @@ export type Business = {
|
||||
ownerId?: string | null;
|
||||
category?: BusinessCategory;
|
||||
images?: BusinessImage[];
|
||||
logoLightUrl?: string | null;
|
||||
logoDarkUrl?: string | null;
|
||||
concurrentCapacity?: number;
|
||||
slotStepMinutes?: number;
|
||||
serviceClassesEnabled?: boolean;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<img
|
||||
v-if="variant === 'mark'"
|
||||
src="/icons/icon-192.png"
|
||||
alt="منتایم"
|
||||
:src="markSrc"
|
||||
:alt="alt"
|
||||
:class="imgClass"
|
||||
/>
|
||||
<template v-else>
|
||||
<img
|
||||
src="/brand/logo-lite.png"
|
||||
alt="منتایم"
|
||||
:src="lightSrc"
|
||||
:alt="alt"
|
||||
:class="['dark:hidden', imgClass]"
|
||||
/>
|
||||
<img
|
||||
src="/brand/logo-dark.png"
|
||||
alt="منتایم"
|
||||
:src="darkSrc"
|
||||
:alt="alt"
|
||||
:class="['hidden dark:block', imgClass]"
|
||||
/>
|
||||
</template>
|
||||
@@ -21,16 +21,22 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
export type LogoVariant = 'auto' | 'mark' | 'horizontal' | 'vertical';
|
||||
import { useAppLogoProps, type LogoVariant } from '@/components/brand/useAppLogo';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
variant?: LogoVariant;
|
||||
class?: string;
|
||||
alt?: string;
|
||||
lightSrc?: string;
|
||||
darkSrc?: string;
|
||||
}>(),
|
||||
{ variant: 'auto' },
|
||||
{
|
||||
variant: 'auto',
|
||||
alt: 'منتایم',
|
||||
},
|
||||
);
|
||||
|
||||
const imgClass = computed(() => props.class ?? 'h-8 w-auto object-contain');
|
||||
const { lightSrc, darkSrc, markSrc } = useAppLogoProps(props);
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { resolveLogoPair } from '@/utils/media';
|
||||
import { usePlatformSettingsStore } from '@/stores/platform-settings';
|
||||
|
||||
export type LogoVariant = 'auto' | 'mark' | 'horizontal' | 'vertical';
|
||||
|
||||
export function useAppLogoProps(
|
||||
props: {
|
||||
variant?: LogoVariant;
|
||||
lightSrc?: string;
|
||||
darkSrc?: string;
|
||||
},
|
||||
) {
|
||||
const platform = usePlatformSettingsStore();
|
||||
|
||||
onMounted(() => {
|
||||
void platform.load();
|
||||
});
|
||||
|
||||
const resolved = computed(() => {
|
||||
if (props.lightSrc || props.darkSrc) {
|
||||
return resolveLogoPair(props.lightSrc, props.darkSrc);
|
||||
}
|
||||
return platform.logoSources;
|
||||
});
|
||||
|
||||
return {
|
||||
lightSrc: computed(() => resolved.value.light),
|
||||
darkSrc: computed(() => resolved.value.dark),
|
||||
markSrc: computed(() => '/icons/icon-192.png'),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="rounded-xl border border-border bg-surface-2 p-3">
|
||||
<p class="mb-2 text-xs font-medium text-muted">{{ label }}</p>
|
||||
|
||||
<div
|
||||
class="flex aspect-[3/1] items-center justify-center overflow-hidden rounded-lg border border-border px-4 py-3"
|
||||
:class="darkPreview ? 'bg-slate-900' : 'bg-white'"
|
||||
>
|
||||
<img :src="previewSrc" alt="" class="max-h-12 w-auto max-w-full object-contain" />
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
<label
|
||||
class="inline-flex cursor-pointer items-center gap-2 rounded-lg bg-brand-600 px-3 py-2 text-xs font-semibold text-white transition hover:bg-brand-700"
|
||||
>
|
||||
<span>{{ uploading ? 'در حال آپلود...' : 'آپلود' }}</span>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/webp,image/gif"
|
||||
class="hidden"
|
||||
:disabled="uploading || removing"
|
||||
@change="onPick"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<button
|
||||
v-if="hasCustom"
|
||||
type="button"
|
||||
class="rounded-lg border border-border px-3 py-2 text-xs text-muted transition hover:border-red-500/40 hover:text-red-600 disabled:opacity-50"
|
||||
:disabled="uploading || removing"
|
||||
@click="emit('remove')"
|
||||
>
|
||||
{{ removing ? 'در حال حذف...' : 'حذف' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
label: string;
|
||||
previewSrc: string;
|
||||
uploading?: boolean;
|
||||
removing?: boolean;
|
||||
hasCustom?: boolean;
|
||||
darkPreview?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
pick: [file: File];
|
||||
remove: [];
|
||||
}>();
|
||||
|
||||
function onPick(event: Event) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
input.value = '';
|
||||
if (file) {
|
||||
emit('pick', file);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-text">لوگوی کسبوکار</label>
|
||||
<p class="mt-1 text-xs text-muted">
|
||||
اختیاری — JPG، PNG یا WebP تا ۵ مگابایت. اگر فقط یکی را بارگذاری کنید، در هر دو حالت روشن و تاریک نمایش داده میشود.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<LogoUploadField
|
||||
label="حالت روشن"
|
||||
:preview-src="lightPreview"
|
||||
:uploading="uploadingLight"
|
||||
:removing="removingLight"
|
||||
:has-custom="!!lightUrl"
|
||||
@pick="(file) => emit('upload-light', file)"
|
||||
@remove="emit('remove-light')"
|
||||
/>
|
||||
<LogoUploadField
|
||||
label="حالت تاریک"
|
||||
:preview-src="darkPreview"
|
||||
:uploading="uploadingDark"
|
||||
:removing="removingDark"
|
||||
:has-custom="!!darkUrl"
|
||||
dark-preview
|
||||
@pick="(file) => emit('upload-dark', file)"
|
||||
@remove="emit('remove-dark')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import LogoUploadField from '@/components/shared/LogoUploadField.vue';
|
||||
import { resolveLogoPair } from '@/utils/media';
|
||||
|
||||
const props = defineProps<{
|
||||
lightUrl?: string | null;
|
||||
darkUrl?: string | null;
|
||||
fallbackLight?: string;
|
||||
fallbackDark?: string;
|
||||
uploadingLight?: boolean;
|
||||
uploadingDark?: boolean;
|
||||
removingLight?: boolean;
|
||||
removingDark?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'upload-light': [file: File];
|
||||
'upload-dark': [file: File];
|
||||
'remove-light': [];
|
||||
'remove-dark': [];
|
||||
}>();
|
||||
|
||||
const resolved = computed(() =>
|
||||
resolveLogoPair(
|
||||
props.lightUrl,
|
||||
props.darkUrl,
|
||||
props.fallbackLight,
|
||||
props.fallbackDark,
|
||||
),
|
||||
);
|
||||
|
||||
const lightPreview = computed(() => resolved.value.light);
|
||||
const darkPreview = computed(() => resolved.value.dark);
|
||||
</script>
|
||||
@@ -0,0 +1,53 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { computed, ref } from 'vue';
|
||||
import { fetchPlatformSettings } from '@/api/platform-settings';
|
||||
import {
|
||||
DEFAULT_LOGO_DARK,
|
||||
DEFAULT_LOGO_LIGHT,
|
||||
resolveLogoPair,
|
||||
} from '@/utils/media';
|
||||
|
||||
export const usePlatformSettingsStore = defineStore('platformSettings', () => {
|
||||
const loginHeroImageUrl = ref<string | null>(null);
|
||||
const logoLightUrl = ref<string | null>(null);
|
||||
const logoDarkUrl = ref<string | null>(null);
|
||||
const loaded = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const logoSources = computed(() =>
|
||||
resolveLogoPair(logoLightUrl.value, logoDarkUrl.value),
|
||||
);
|
||||
|
||||
async function load(force = false) {
|
||||
if (loaded.value && !force) return;
|
||||
if (loading.value) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = await fetchPlatformSettings();
|
||||
loginHeroImageUrl.value = data.loginHeroImageUrl;
|
||||
logoLightUrl.value = data.logoLightUrl;
|
||||
logoDarkUrl.value = data.logoDarkUrl;
|
||||
loaded.value = true;
|
||||
} catch {
|
||||
loginHeroImageUrl.value = null;
|
||||
logoLightUrl.value = null;
|
||||
logoDarkUrl.value = null;
|
||||
loaded.value = true;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loginHeroImageUrl,
|
||||
logoLightUrl,
|
||||
logoDarkUrl,
|
||||
defaultLogoLight: DEFAULT_LOGO_LIGHT,
|
||||
defaultLogoDark: DEFAULT_LOGO_DARK,
|
||||
logoSources,
|
||||
loaded,
|
||||
loading,
|
||||
load,
|
||||
};
|
||||
});
|
||||
@@ -19,3 +19,32 @@ export function businessCoverUrl(
|
||||
const cover = images.find((i) => i.isCover) ?? images[0];
|
||||
return uploadUrl(cover?.url) || null;
|
||||
}
|
||||
|
||||
export const DEFAULT_LOGO_LIGHT = '/brand/logo-lite.png';
|
||||
export const DEFAULT_LOGO_DARK = '/brand/logo-dark.png';
|
||||
|
||||
export type LogoSourcePair = {
|
||||
light: string;
|
||||
dark: string;
|
||||
};
|
||||
|
||||
export function resolveLogoPair(
|
||||
lightUrl: string | null | undefined,
|
||||
darkUrl: string | null | undefined,
|
||||
fallbackLight = DEFAULT_LOGO_LIGHT,
|
||||
fallbackDark = DEFAULT_LOGO_DARK,
|
||||
): LogoSourcePair {
|
||||
const light = uploadUrl(lightUrl);
|
||||
const dark = uploadUrl(darkUrl);
|
||||
|
||||
if (light && dark) {
|
||||
return { light, dark };
|
||||
}
|
||||
if (light && !dark) {
|
||||
return { light, dark: light };
|
||||
}
|
||||
if (!light && dark) {
|
||||
return { light: dark, dark };
|
||||
}
|
||||
return { light: fallbackLight, dark: fallbackDark };
|
||||
}
|
||||
|
||||
@@ -131,6 +131,20 @@
|
||||
@remove-existing="onRemoveImage"
|
||||
/>
|
||||
|
||||
<LogoUploadPair
|
||||
v-if="editingId && detailBusiness"
|
||||
:light-url="detailBusiness.logoLightUrl"
|
||||
:dark-url="detailBusiness.logoDarkUrl"
|
||||
:uploading-light="uploadingLogoLight"
|
||||
:uploading-dark="uploadingLogoDark"
|
||||
:removing-light="removingLogoLight"
|
||||
:removing-dark="removingLogoDark"
|
||||
@upload-light="onUploadLogoLight"
|
||||
@upload-dark="onUploadLogoDark"
|
||||
@remove-light="onRemoveLogoLight"
|
||||
@remove-dark="onRemoveLogoDark"
|
||||
/>
|
||||
|
||||
<BusinessServicesSection
|
||||
v-if="editingId && form.categoryId"
|
||||
:business-id="editingId"
|
||||
@@ -221,13 +235,18 @@ import {
|
||||
deleteBusinessImage,
|
||||
fetchBusiness,
|
||||
fetchBusinesses,
|
||||
removeBusinessLogoDark,
|
||||
removeBusinessLogoLight,
|
||||
updateBusiness,
|
||||
uploadBusinessImages,
|
||||
uploadBusinessLogoDark,
|
||||
uploadBusinessLogoLight,
|
||||
} from '@/api/businesses';
|
||||
import { fetchUser, fetchUsers } from '@/api/users';
|
||||
import type { Business, BusinessCategory, User } from '@/api/types';
|
||||
import { ApiError } from '@/api/client';
|
||||
import BusinessImageUpload from '@/components/admin/BusinessImageUpload.vue';
|
||||
import LogoUploadPair from '@/components/shared/LogoUploadPair.vue';
|
||||
import BusinessListCard from '@/components/admin/BusinessListCard.vue';
|
||||
import BusinessServicesSection from '@/components/admin/BusinessServicesSection.vue';
|
||||
import AppBadge from '@/components/ui/AppBadge.vue';
|
||||
@@ -265,6 +284,10 @@ const isEditMode = ref(false);
|
||||
const detailBusiness = ref<Business | null>(null);
|
||||
const imageUploadRef = ref<InstanceType<typeof BusinessImageUpload> | null>(null);
|
||||
const deletingImageId = ref<string | null>(null);
|
||||
const uploadingLogoLight = ref(false);
|
||||
const uploadingLogoDark = ref(false);
|
||||
const removingLogoLight = ref(false);
|
||||
const removingLogoDark = ref(false);
|
||||
|
||||
const assignOpen = ref(false);
|
||||
const assignTarget = ref<Business | null>(null);
|
||||
@@ -460,6 +483,68 @@ async function onRemoveImage(imageId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshDetailBusiness() {
|
||||
if (!editingId.value) return;
|
||||
detailBusiness.value = await fetchBusiness(editingId.value);
|
||||
await load();
|
||||
}
|
||||
|
||||
async function onUploadLogoLight(file: File) {
|
||||
if (!editingId.value) return;
|
||||
uploadingLogoLight.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
await uploadBusinessLogoLight(editingId.value, file);
|
||||
await refreshDetailBusiness();
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'آپلود لوگو ناموفق بود';
|
||||
} finally {
|
||||
uploadingLogoLight.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onUploadLogoDark(file: File) {
|
||||
if (!editingId.value) return;
|
||||
uploadingLogoDark.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
await uploadBusinessLogoDark(editingId.value, file);
|
||||
await refreshDetailBusiness();
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'آپلود لوگو ناموفق بود';
|
||||
} finally {
|
||||
uploadingLogoDark.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onRemoveLogoLight() {
|
||||
if (!editingId.value) return;
|
||||
removingLogoLight.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
await removeBusinessLogoLight(editingId.value);
|
||||
await refreshDetailBusiness();
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'حذف لوگو ناموفق بود';
|
||||
} finally {
|
||||
removingLogoLight.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onRemoveLogoDark() {
|
||||
if (!editingId.value) return;
|
||||
removingLogoDark.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
await removeBusinessLogoDark(editingId.value);
|
||||
await refreshDetailBusiness();
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'حذف لوگو ناموفق بود';
|
||||
} finally {
|
||||
removingLogoDark.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onTitleBlur() {
|
||||
if (!isEditMode.value && !editingId.value) {
|
||||
form.value.slug = slugify(form.value.title);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<section class="space-y-2">
|
||||
<h1 class="text-xl font-bold text-text">تنظیمات پلتفرم</h1>
|
||||
<p class="text-sm text-muted">
|
||||
تصویر پسزمینه صفحه ورود دسکتاپ را از اینجا مدیریت کنید.
|
||||
لوگوی اصلی پلتفرم و تصویر صفحه ورود دسکتاپ را از اینجا مدیریت کنید.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -21,6 +21,29 @@
|
||||
{{ success }}
|
||||
</p>
|
||||
|
||||
<section class="mt-6 rounded-2xl border border-border bg-surface-2 p-4 lg:p-6">
|
||||
<h2 class="text-base font-semibold text-text">لوگوی اصلی منتایم</h2>
|
||||
<p class="mt-1 text-xs text-muted">
|
||||
در صفحه اصلی و جاهایی که لوگوی کسبوکار تنظیم نشده نمایش داده میشود.
|
||||
</p>
|
||||
|
||||
<div v-if="loading" class="mt-4 text-sm text-muted">در حال بارگذاری...</div>
|
||||
<LogoUploadPair
|
||||
v-else
|
||||
class="mt-4"
|
||||
:light-url="settings?.logoLightUrl"
|
||||
:dark-url="settings?.logoDarkUrl"
|
||||
:uploading-light="uploadingLogoLight"
|
||||
:uploading-dark="uploadingLogoDark"
|
||||
:removing-light="removingLogoLight"
|
||||
:removing-dark="removingLogoDark"
|
||||
@upload-light="onUploadLogoLight"
|
||||
@upload-dark="onUploadLogoDark"
|
||||
@remove-light="onRemoveLogoLight"
|
||||
@remove-dark="onRemoveLogoDark"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section class="mt-6 rounded-2xl border border-border bg-surface-2 p-4 lg:p-6">
|
||||
<h2 class="text-base font-semibold text-text">تصویر صفحه ورود (دسکتاپ)</h2>
|
||||
<p class="mt-1 text-xs text-muted">
|
||||
@@ -85,21 +108,33 @@ import { computed, onMounted, ref } from 'vue';
|
||||
import {
|
||||
fetchPlatformSettings,
|
||||
removeLoginHeroImage,
|
||||
removePlatformLogoDark,
|
||||
removePlatformLogoLight,
|
||||
uploadLoginHeroImage,
|
||||
uploadPlatformLogoDark,
|
||||
uploadPlatformLogoLight,
|
||||
type PlatformSettings,
|
||||
} from '@/api/platform-settings';
|
||||
import { ApiError } from '@/api/client';
|
||||
import AppButton from '@/components/ui/AppButton.vue';
|
||||
import AppIcon from '@/components/ui/AppIcon.vue';
|
||||
import LogoUploadPair from '@/components/shared/LogoUploadPair.vue';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import { usePlatformSettingsStore } from '@/stores/platform-settings';
|
||||
import { uploadUrl } from '@/utils/media';
|
||||
|
||||
const platformStore = usePlatformSettingsStore();
|
||||
|
||||
const DEFAULT_PREVIEW = '/landing/hero-car-wash.jpg';
|
||||
|
||||
const settings = ref<PlatformSettings | null>(null);
|
||||
const loading = ref(true);
|
||||
const uploading = ref(false);
|
||||
const removing = ref(false);
|
||||
const uploadingLogoLight = ref(false);
|
||||
const uploadingLogoDark = ref(false);
|
||||
const removingLogoLight = ref(false);
|
||||
const removingLogoDark = ref(false);
|
||||
const error = ref('');
|
||||
const success = ref('');
|
||||
|
||||
@@ -157,6 +192,66 @@ async function onRemove() {
|
||||
}
|
||||
}
|
||||
|
||||
async function onUploadLogoLight(file: File) {
|
||||
uploadingLogoLight.value = true;
|
||||
error.value = '';
|
||||
success.value = '';
|
||||
try {
|
||||
settings.value = await uploadPlatformLogoLight(file);
|
||||
await platformStore.load(true);
|
||||
success.value = 'لوگوی حالت روشن بهروزرسانی شد.';
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'آپلود لوگو ناموفق بود.';
|
||||
} finally {
|
||||
uploadingLogoLight.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onUploadLogoDark(file: File) {
|
||||
uploadingLogoDark.value = true;
|
||||
error.value = '';
|
||||
success.value = '';
|
||||
try {
|
||||
settings.value = await uploadPlatformLogoDark(file);
|
||||
await platformStore.load(true);
|
||||
success.value = 'لوگوی حالت تاریک بهروزرسانی شد.';
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'آپلود لوگو ناموفق بود.';
|
||||
} finally {
|
||||
uploadingLogoDark.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onRemoveLogoLight() {
|
||||
removingLogoLight.value = true;
|
||||
error.value = '';
|
||||
success.value = '';
|
||||
try {
|
||||
settings.value = await removePlatformLogoLight();
|
||||
await platformStore.load(true);
|
||||
success.value = 'لوگوی حالت روشن حذف شد.';
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'حذف لوگو ناموفق بود.';
|
||||
} finally {
|
||||
removingLogoLight.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onRemoveLogoDark() {
|
||||
removingLogoDark.value = true;
|
||||
error.value = '';
|
||||
success.value = '';
|
||||
try {
|
||||
settings.value = await removePlatformLogoDark();
|
||||
await platformStore.load(true);
|
||||
success.value = 'لوگوی حالت تاریک حذف شد.';
|
||||
} catch (e) {
|
||||
error.value = e instanceof ApiError ? e.message : 'حذف لوگو ناموفق بود.';
|
||||
} finally {
|
||||
removingLogoDark.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void load();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user