Files
Montech_Landing/apps/adm/src/views/SettingsView.vue
T
MahdiandCursor e9eafdaabc Fix landing 500 from invalid Asia/Esfahan timezone.
Normalize Iran city aliases to Asia/Tehran, harden the clock, and make settings timezone a safe select.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-30 21:25:45 +03:30

134 lines
4.6 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<h1>تنظیمات سایت</h1>
<form v-if="form" class="card" @submit.prevent="save">
<div class="grid-2">
<div class="field">
<label class="label">نام برند</label>
<input v-model="form.brandName" class="input" />
</div>
<div class="field">
<label class="label">تگ‌لاین</label>
<input v-model="form.tagline" class="input" />
</div>
<div class="field">
<label class="label">ایمیل</label>
<input v-model="form.email" class="input" dir="ltr" />
</div>
<div class="field">
<label class="label">تلفن</label>
<input v-model="form.phone" class="input" dir="ltr" />
</div>
<div class="field">
<label class="label">آدرس</label>
<input v-model="form.address" class="input" />
</div>
<div class="field">
<label class="label">منطقه زمانی</label>
<select v-model="form.timezone" class="input" dir="ltr">
<option value="Asia/Tehran">Asia/Tehran (ایران — تهران، اصفهان، مشهد و …)</option>
<option value="UTC">UTC</option>
</select>
<p class="muted" style="margin-top: 0.35rem">برای همهٔ شهرهای ایران فقط Asia/Tehran معتبر است.</p>
</div>
<div class="field" style="grid-column: 1 / -1">
<label class="label">آدرس لوگو</label>
<input v-model="form.logoUrl" class="input" dir="ltr" placeholder="از بخش رسانه آپلود کنید و آدرس را اینجا بگذارید" />
</div>
</div>
<h2 style="margin: 1.25rem 0 0.75rem; font-size: 1rem">شبکه‌های اجتماعی</h2>
<div v-for="(s, i) in socials" :key="i" class="item-box">
<div class="row" style="justify-content: space-between; margin-bottom: 0.5rem">
<strong>مورد {{ i + 1 }}</strong>
<button type="button" class="btn danger" @click="socials.splice(i, 1)">حذف</button>
</div>
<div class="grid-2">
<div class="field">
<label class="label">نام (مثلاً لینکدین)</label>
<input v-model="s.label" class="input" />
</div>
<div class="field">
<label class="label">آدرس لینک</label>
<input v-model="s.url" class="input" dir="ltr" placeholder="https://..." />
</div>
</div>
</div>
<button type="button" class="btn ghost" @click="socials.push({ label: '', url: '' })">+ افزودن شبکه اجتماعی</button>
<p v-if="msg" class="muted" style="margin-top: 1rem">{{ msg }}</p>
<button class="btn" style="margin-top: 0.75rem">ذخیره</button>
</form>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { api } from "../lib/api";
const form = ref<{
brandName: string;
tagline: string;
email: string;
phone: string;
address: string;
timezone: string;
logoUrl: string;
} | null>(null);
const socials = reactive<Array<{ label: string; url: string }>>([]);
const msg = ref("");
onMounted(async () => {
const { data } = await api.get("/admin/settings");
form.value = {
brandName: data.brandName || "",
tagline: data.tagline || "",
email: data.email || "",
phone: data.phone || "",
address: data.address || "",
timezone: data.timezone || "Asia/Tehran",
logoUrl: data.logoUrl || "",
};
socials.splice(0, socials.length, ...(Array.isArray(data.socials) ? data.socials : []));
if (!socials.length) socials.push({ label: "", url: "" });
});
async function save() {
if (!form.value) return;
msg.value = "";
try {
const payload = {
brandName: form.value.brandName,
tagline: form.value.tagline,
email: form.value.email,
phone: form.value.phone,
address: form.value.address,
timezone: form.value.timezone,
logoUrl: form.value.logoUrl || null,
socials: socials.filter((s) => s.label.trim() || s.url.trim()),
};
const { data } = await api.put("/admin/settings", payload);
form.value.logoUrl = data.logoUrl || "";
msg.value = "ذخیره شد.";
} catch (e: any) {
const detail = e?.response?.data?.message;
msg.value = Array.isArray(detail)
? `خطا: ${detail.join("، ")}`
: detail
? `خطا: ${detail}`
: "خطا در ذخیره.";
}
}
</script>
<style scoped>
.item-box {
border: 1px solid var(--border);
border-radius: 10px;
padding: 0.9rem;
margin-bottom: 0.9rem;
background: #12151b;
}
</style>