Wire live business contact data and refresh homepage/about branding.

Pull landline, cell, and address from Meshkee business-info across footer and contact surfaces, update brand spelling and 14-year messaging, and keep product cards free of placeholder call-to-action pricing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-10-05 00:08:45 +03:30
co-authored by Cursor
parent 3ffa43641d
commit e2468a1ba1
23 changed files with 499 additions and 228 deletions
+6
View File
@@ -20,6 +20,12 @@ Meshkee Website API (`https://api.meshkee.com/api/v1`, docs at
sharing the same display name under different ids (backend data-entry
artifact). The summary merges by name and links to whichever id holds
the most products under that name.
- Business contact data (`getBusinessInfo` /
`getResolvedBusinessContact`) comes from
`GET /tenants/{domain}/website/business-info` — landline/cell
(`phoneNumbers`), addresses, emails, social. Footer, contact page,
and `HomeContactStrip` consume the resolved helper. Empty/failed
fetches keep the previous hardcoded address and phone fallbacks.
## Static image slots (business-managed overrides)
+14
View File
@@ -31,6 +31,20 @@ Dashboard import catalog: `GET /meshkee/static-image-slots` (`src/app/meshkee/st
If a rendered image size or crop ratio changes, update both the component container (`aspectRatioToCss`) and the matching catalog entry.
## Business contact (business-info)
`GET /tenants/aradarisman.com/website/business-info` → `getBusinessInfo` /
`getResolvedBusinessContact` in `src/lib/meshkee.ts`.
| Field | UI |
|---|---|
| `phoneNumbers` (`landline` / `cell`) | Footer, `ContactInfo`, `HomeContactStrip` |
| `addresses[0]` | Footer, `ContactInfo` (map pin is fixed coords on contact page) |
| `emails` | Footer |
| `socialMedia` | Contact page social icons (when set) |
Failed/empty responses keep local address + phone fallbacks so the page never blanks out.
## Other conventions
- Category tiles from live products (`getCategorySummary`) because the raw `/categories` taxonomy has duplicate display names.
+62 -34
View File
@@ -4,36 +4,54 @@ import Link from "next/link";
import Container from "@/components/Container";
import PageBanner from "@/components/PageBanner";
import MissionVision from "@/components/MissionVision";
import ImportCountries from "@/components/ImportCountries";
import Features from "@/components/Features";
import { pageMetadata } from "@/lib/seo";
import {
getResolvedBusinessContact,
phoneTelHref,
} from "@/lib/meshkee";
export const metadata: Metadata = pageMetadata({
title: "درباره ما | آراد آریسمان",
title: "درباره ما | آراد اَریسمان",
description:
"آشنایی با شرکت آراد آریسمان؛ بیش از ۲۳ سال تجربه در تولید و عرضه مکمل‌های غذایی دام، طیور و زنبور عسل.",
"آشنایی با شرکت آراد اَریسمان؛ بیش از ۲۳ سال تجربه در تولید و عرضه مکمل‌های غذایی دام، طیور و زنبور عسل.",
path: "/about",
});
export default function AboutPage() {
export default async function AboutPage() {
const contact = await getResolvedBusinessContact();
const phone = contact.primaryPhone;
return (
<>
<PageBanner
title="درباره آراد آریسمان"
title="درباره آراد اَریسمان"
subtitle="بیش از دو دهه تجربه در تولید و عرضه مکمل‌های غذایی دام، طیور و زنبور عسل"
breadcrumb="درباره ما"
/>
<section className="py-16 sm:py-20">
<Container className="grid grid-cols-1 lg:grid-cols-2 items-center gap-12">
<div className="relative aspect-[4/3] rounded-3xl overflow-hidden shadow-xl bg-surface order-2 lg:order-1">
<div className="relative aspect-[4/3] rounded-3xl overflow-hidden shadow-xl bg-secondary order-2 lg:order-1">
<Image
src="/images/category-3.jpg"
alt="محصولات آراد آریسمان"
src="/images/stats-banner.jpg"
alt=""
fill
className="object-contain p-6"
className="object-cover scale-110 blur-[6px]"
sizes="(min-width: 1024px) 45vw, 90vw"
aria-hidden
/>
<div className="absolute inset-0 bg-primary-dark/45" aria-hidden />
<div className="absolute inset-0 flex items-center justify-center p-10">
<Image
src="/images/footer-logo.png"
alt="آراد اَریسمان"
width={220}
height={62}
className="relative z-10 h-auto w-44 sm:w-52 drop-shadow-lg"
priority
/>
</div>
</div>
<div className="order-1 lg:order-2 text-center lg:text-start">
@@ -42,7 +60,7 @@ export default function AboutPage() {
تغذیه مطمئن، پرورش موفق
</h2>
<p className="mt-6 leading-8 text-foreground">
شرکت آراد آریسمان پیشرو در تولید و عرضه افزودنی‌های خوراک، ویتامین‌ها و
شرکت آراد اَریسمان پیشرو در تولید و عرضه افزودنی‌های خوراک، ویتامین‌ها و
مکمل‌های غذایی دام و طیور با بیش از ۲۳ سال فعالیت در بازار ایران می‌باشد.
واردات این شرکت عمدتا از تولیدکنندگان معتبر بین‌المللی غذای دام و طیور از
کشورهای انگلستان، فرانسه، ترکیه، هندوستان و چین می‌باشد.
@@ -53,18 +71,28 @@ export default function AboutPage() {
نتیجه‌ی این رویکرد، اعتماد پایدار بیش از ۲۳۰ مشتری در سراسر کشور است.
</p>
<div className="mt-8 flex justify-center lg:justify-start gap-10">
<div>
<div className="text-3xl font-extrabold text-primary">۲۳+</div>
<div className="mt-1 text-sm text-foreground">سال تجربه</div>
</div>
<div>
<div className="text-3xl font-extrabold text-primary">۲۳۰+</div>
<div className="mt-1 text-sm text-foreground">رضایت مشتری</div>
</div>
<div>
<div className="text-3xl font-extrabold text-primary">۵</div>
<div className="mt-1 text-sm text-foreground">کشور واردات</div>
<div className="mt-8 flex justify-center lg:justify-start">
<div className="inline-flex items-center gap-4 sm:gap-5">
<div className="shrink-0 text-center lg:text-start">
<p className="text-4xl sm:text-5xl font-extrabold tracking-tight leading-none text-primary">
۱۴ سال
</p>
<p
dir="ltr"
className="mt-1.5 font-display text-xs sm:text-sm font-medium tracking-[0.06em] text-primary/55"
>
14 years of experience
</p>
</div>
<div
className="hidden sm:block h-12 w-px shrink-0 bg-primary/20"
aria-hidden
/>
<p className="text-sm sm:text-base font-medium leading-7 text-foreground text-start">
تولید تخصصی محصولات
<br />
مکمل دام و طیور
</p>
</div>
</div>
</div>
@@ -75,16 +103,14 @@ export default function AboutPage() {
<section className="bg-surface">
<Container className="pt-16 sm:pt-20 text-center max-w-xl mx-auto">
<span className="text-sm font-bold text-accent">چرا آراد آریسمان</span>
<span className="text-sm font-bold text-accent">چرا آراد اَریسمان</span>
<h2 className="mt-3 text-3xl sm:text-4xl font-extrabold text-primary">
مزایای مکمل‌های آراد آریسمان
مزایای مکمل‌های آراد اَریسمان
</h2>
</Container>
<Features />
</section>
<ImportCountries />
<section className="py-16 sm:py-20">
<Container>
<div className="rounded-3xl bg-primary px-8 py-14 sm:px-16 text-center">
@@ -92,7 +118,7 @@ export default function AboutPage() {
برای مشاوره و خرید محصولات همین حالا با ما در تماس باشید
</h2>
<p className="mt-4 text-white/80 max-w-xl mx-auto">
کارشناسان آراد آریسمان آماده پاسخگویی به سوالات شما درباره مکمل‌ها و
کارشناسان آراد اَریسمان آماده پاسخگویی به سوالات شما درباره مکمل‌ها و
نحوه مصرف آن‌ها هستند.
</p>
<div className="mt-8 flex flex-wrap justify-center gap-4">
@@ -102,13 +128,15 @@ export default function AboutPage() {
>
تماس با ما
</Link>
<a
href="tel:09104067935"
dir="ltr"
className="rounded-full border border-white/30 px-7 py-3.5 text-white font-semibold hover:bg-white/10 transition-colors"
>
09104067935
</a>
{phone ? (
<a
href={phoneTelHref(phone.number)}
dir="ltr"
className="rounded-full border border-white/30 px-7 py-3.5 text-white font-semibold hover:bg-white/10 transition-colors"
>
{phone.number}
</a>
) : null}
</div>
</div>
</Container>
+2 -2
View File
@@ -31,7 +31,7 @@ export async function generateMetadata({
if (!post) return {};
const title = postTitle(post);
return pageMetadata({
title: `${title} | آراد آریسمان`,
title: `${title} | آراد اَریسمان`,
description: postExcerpt(post, 160),
path: blogPath(post),
});
@@ -114,7 +114,7 @@ export default async function BlogDetailPage({
<div className="mt-10 rounded-2xl bg-surface p-6 flex flex-wrap items-center justify-between gap-4">
<div>
<p className="font-bold text-secondary">نویسنده: تیم آراد آریسمان</p>
<p className="font-bold text-secondary">نویسنده: تیم آراد اَریسمان</p>
<p className="mt-1 text-sm text-foreground">
برای مشاوره تخصصی تغذیه دام و طیور با ما در تماس باشید.
</p>
+3 -3
View File
@@ -6,9 +6,9 @@ import Pagination from "@/components/Pagination";
import { getPosts } from "@/lib/meshkee";
export const metadata = pageMetadata({
title: "مقالات | آراد آریسمان",
title: "مقالات | آراد اَریسمان",
description:
"مقالات آموزشی درباره تغذیه دام، طیور و زنبور عسل از تیم آراد آریسمان.",
"مقالات آموزشی درباره تغذیه دام، طیور و زنبور عسل از تیم آراد اَریسمان.",
path: "/blog",
});
@@ -33,7 +33,7 @@ export default async function BlogPage({
return (
<>
<PageBanner
title="مقالات آراد آریسمان"
title="مقالات آراد اَریسمان"
subtitle="نکات آموزشی و تخصصی درباره تغذیه دام، طیور و زنبور عسل"
breadcrumb="مقالات"
/>
+80 -45
View File
@@ -3,24 +3,49 @@ import PageBanner from "@/components/PageBanner";
import ContactInfo from "@/components/ContactInfo";
import ContactForm from "@/components/ContactForm";
import { pageMetadata } from "@/lib/seo";
import {
getResolvedBusinessContact,
phoneTelHref,
} from "@/lib/meshkee";
export const metadata = pageMetadata({
title: "تماس با ما | آراد آریسمان",
title: "تماس با ما | آراد اَریسمان",
description:
"راه‌های ارتباطی با شرکت آراد آریسمان؛ آدرس، تلفن تماس و فرم ارسال پیام.",
"راه‌های ارتباطی با شرکت آراد اَریسمان؛ آدرس، تلفن تماس و فرم ارسال پیام.",
path: "/contact",
});
const mapQuery = encodeURIComponent(
"قم، شهرک صنعتی شکوهیه، خیابان شهید بروجردی"
);
function telegramHref(handle: string): string {
const trimmed = handle.trim();
if (!trimmed) return "#";
if (trimmed.startsWith("http")) return trimmed;
return `https://t.me/${trimmed.replace(/^@/, "")}`;
}
function whatsappHref(value: string): string {
const trimmed = value.trim();
if (!trimmed) return "#";
if (trimmed.startsWith("http")) return trimmed;
const digits = trimmed
.replace(/[۰-۹]/g, (d) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(d)))
.replace(/[^\d]/g, "");
return digits ? `https://wa.me/${digits}` : "#";
}
const MAP_LAT = 34.79998060691881;
const MAP_LNG = 50.8027208051919;
export default async function ContactPage() {
const contact = await getResolvedBusinessContact();
const telegram = contact.socialMedia.telegram?.trim() || "";
const whatsapp = contact.socialMedia.whatsapp?.trim() || "";
const primaryPhone = contact.primaryPhone;
export default function ContactPage() {
return (
<>
<PageBanner
title="تماس با ما"
subtitle="سوالات، پیشنهادات یا درخواست مشاوره خود را برای ما بفرستید؛ کارشناسان آراد آریسمان در اسرع وقت پاسخگوی شما خواهند بود."
subtitle="سوالات، پیشنهادات یا درخواست مشاوره خود را برای ما بفرستید؛ کارشناسان آراد اَریسمان در اسرع وقت پاسخگوی شما خواهند بود."
breadcrumb="تماس با ما"
/>
@@ -44,8 +69,8 @@ export default function ContactPage() {
<div className="lg:col-span-2 flex flex-col gap-5">
<div className="relative flex-1 min-h-[280px] rounded-2xl overflow-hidden border border-black/5 shadow-sm">
<iframe
title="نقشه آراد آریسمان"
src={`https://www.google.com/maps?q=${mapQuery}&output=embed`}
title="نقشه آراد اَریسمان"
src={`https://www.google.com/maps?q=${MAP_LAT},${MAP_LNG}&z=17&output=embed`}
className="absolute inset-0 h-full w-full border-0"
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
@@ -55,42 +80,52 @@ export default function ContactPage() {
<div className="rounded-2xl bg-secondary p-7 text-white">
<h3 className="font-bold">ما را در شبکه‌های اجتماعی دنبال کنید</h3>
<div className="mt-5 flex items-center gap-4">
<a
href="#"
aria-label="تلگرام"
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path
d="M21.5 3.5 2.8 10.9c-1 .4-1 1.7.1 2l4.7 1.5 1.8 5.6c.2.6 1 .8 1.4.3l2.5-2.7 4.9 3.6c.6.5 1.6.1 1.8-.6l3-15.6c.2-1-.7-1.8-1.5-1.5z"
fill="currentColor"
/>
</svg>
</a>
<a
href="#"
aria-label="واتساپ"
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path
d="M12 2a10 10 0 0 0-8.6 15.1L2 22l5-1.4A10 10 0 1 0 12 2Zm0 18.2a8.1 8.1 0 0 1-4.2-1.1l-.3-.2-3 .8.8-2.9-.2-.3A8.2 8.2 0 1 1 12 20.2Zm4.5-6.1c-.2-.1-1.5-.7-1.7-.8-.2-.1-.4-.1-.6.1-.2.2-.7.8-.8 1-.2.2-.3.2-.5.1a6.7 6.7 0 0 1-2-1.2 7.4 7.4 0 0 1-1.4-1.7c-.1-.2 0-.4.1-.5l.4-.4c.1-.2.2-.3.2-.5.1-.2 0-.4 0-.5-.1-.1-.6-1.5-.8-2-.2-.5-.4-.4-.6-.4h-.5c-.2 0-.5.1-.7.3-.2.2-.9.9-.9 2.2s.9 2.6 1.1 2.8c.1.2 1.9 3 4.7 4.1.7.3 1.2.4 1.6.6.7.2 1.3.2 1.8.1.5-.1 1.5-.6 1.7-1.2.2-.6.2-1.1.2-1.2-.1-.2-.3-.2-.5-.3Z"
fill="currentColor"
/>
</svg>
</a>
<a
href="tel:09104067935"
aria-label="تماس تلفنی"
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
</a>
{telegram ? (
<a
href={telegramHref(telegram)}
target="_blank"
rel="noopener noreferrer"
aria-label="تلگرام"
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path
d="M21.5 3.5 2.8 10.9c-1 .4-1 1.7.1 2l4.7 1.5 1.8 5.6c.2.6 1 .8 1.4.3l2.5-2.7 4.9 3.6c.6.5 1.6.1 1.8-.6l3-15.6c.2-1-.7-1.8-1.5-1.5z"
fill="currentColor"
/>
</svg>
</a>
) : null}
{whatsapp ? (
<a
href={whatsappHref(whatsapp)}
target="_blank"
rel="noopener noreferrer"
aria-label="واتساپ"
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path
d="M12 2a10 10 0 0 0-8.6 15.1L2 22l5-1.4A10 10 0 1 0 12 2Zm0 18.2a8.1 8.1 0 0 1-4.2-1.1l-.3-.2-3 .8.8-2.9-.2-.3A8.2 8.2 0 1 1 12 20.2Zm4.5-6.1c-.2-.1-1.5-.7-1.7-.8-.2-.1-.4-.1-.6.1-.2.2-.7.8-.8 1-.2.2-.3.2-.5.1a6.7 6.7 0 0 1-2-1.2 7.4 7.4 0 0 1-1.4-1.7c-.1-.2 0-.4.1-.5l.4-.4c.1-.2.2-.3.2-.5.1-.2 0-.4 0-.5-.1-.1-.6-1.5-.8-2-.2-.5-.4-.4-.6-.4h-.5c-.2 0-.5.1-.7.3-.2.2-.9.9-.9 2.2s.9 2.6 1.1 2.8c.1.2 1.9 3 4.7 4.1.7.3 1.2.4 1.6.6.7.2 1.3.2 1.8.1.5-.1 1.5-.6 1.7-1.2.2-.6.2-1.1.2-1.2-.1-.2-.3-.2-.5-.3Z"
fill="currentColor"
/>
</svg>
</a>
) : null}
{primaryPhone ? (
<a
href={phoneTelHref(primaryPhone.number)}
aria-label="تماس تلفنی"
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
</a>
) : null}
</div>
</div>
</div>
+2 -2
View File
@@ -28,11 +28,11 @@ export async function generateMetadata(): Promise<Metadata> {
return {
metadataBase: new URL(SITE_URL),
title: {
default: "آراد آریسمان",
default: "آراد اَریسمان",
template: "%s",
},
description:
"شرکت آراد آریسمان، تولید و عرضه مکمل‌ها، ویتامین‌ها و افزودنی‌های خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
"شرکت آراد اَریسمان، تولید و عرضه مکمل‌ها، ویتامین‌ها و افزودنی‌های خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
icons: {
icon: iconUrl,
shortcut: iconUrl,
+3 -3
View File
@@ -11,9 +11,9 @@ import { categoryPath, resolveCategorySlotHref } from "@/lib/urls";
import { pageMetadata } from "@/lib/seo";
export const metadata: Metadata = pageMetadata({
title: "آراد آریسمان | صفحه اصلی",
title: "آراد اَریسمان | صفحه اصلی",
description:
"شرکت آراد آریسمان، تولید و عرضه مکمل‌ها، ویتامین‌ها و افزودنی‌های خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
"شرکت آراد اَریسمان، تولید و عرضه مکمل‌ها، ویتامین‌ها و افزودنی‌های خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
path: "/",
});
@@ -48,7 +48,7 @@ export default async function Home() {
<HomeContactStrip />
<CategoryProducts
categoryNameEn="Poultry"
className="py-14 sm:py-16"
className="py-14 sm:py-16 bg-[#fbf8f3]"
/>
<Features />
<Stats />
+17 -9
View File
@@ -12,6 +12,8 @@ import {
getCategoryAncestors,
getProductById,
getProducts,
getResolvedBusinessContact,
phoneTelHref,
productCatalog,
productImages,
productPriceLabel,
@@ -33,7 +35,7 @@ export async function generateMetadata({
if (!product) return {};
const description = product.summary || stripHtml(product.descriptionHtml, 160);
return pageMetadata({
title: `${product.nameFa} | آراد آریسمان`,
title: `${product.nameFa} | آراد اَریسمان`,
description,
path: productPath(product),
});
@@ -58,7 +60,11 @@ export default async function ProductDetailPage({
const catalog = productCatalog(product);
const shortDesc = product.summary || stripHtml(product.descriptionHtml, 160);
const allCategories = await getCategories();
const [allCategories, contact] = await Promise.all([
getCategories(),
getResolvedBusinessContact(),
]);
const phone = contact.primaryPhone;
const categoryTrail = product.categoryId
? getCategoryAncestors(product.categoryId, allCategories)
: [];
@@ -121,13 +127,15 @@ export default async function ProductDetailPage({
</div>
<div className="mt-6 flex flex-wrap gap-3">
<a
href="tel:09104067935"
dir="ltr"
className="rounded-full bg-primary px-7 py-3.5 text-white font-semibold hover:bg-primary-dark transition-colors"
>
09104067935
</a>
{phone ? (
<a
href={phoneTelHref(phone.number)}
dir="ltr"
className="rounded-full bg-primary px-7 py-3.5 text-white font-semibold hover:bg-primary-dark transition-colors"
>
{phone.number}
</a>
) : null}
<Link
href="/contact"
className="rounded-full border border-primary/30 px-7 py-3.5 text-primary font-semibold hover:bg-primary/5 transition-colors"
@@ -30,8 +30,8 @@ export async function generateMetadata({
const category = await getCategoryById(id);
if (!category) return {};
return pageMetadata({
title: `${category.nameFa} | محصولات آراد آریسمان`,
description: `مشاهده محصولات دسته ${category.nameFa}؛ مکمل‌های غذایی آراد آریسمان.`,
title: `${category.nameFa} | محصولات آراد اَریسمان`,
description: `مشاهده محصولات دسته ${category.nameFa}؛ مکمل‌های غذایی آراد اَریسمان.`,
path: categoryPath(category),
});
}
+3 -3
View File
@@ -11,9 +11,9 @@ import { categoryPath } from "@/lib/urls";
import { slugifyFa } from "@/lib/slugify";
export const metadata = pageMetadata({
title: "محصولات | آراد آریسمان",
title: "محصولات | آراد اَریسمان",
description:
"مکمل‌های غذایی، ویتامینه و معدنی دام، طیور و زنبور عسل؛ محصولات آراد آریسمان را مشاهده کنید.",
"مکمل‌های غذایی، ویتامینه و معدنی دام، طیور و زنبور عسل؛ محصولات آراد اَریسمان را مشاهده کنید.",
path: "/products",
});
@@ -62,7 +62,7 @@ export default async function ProductsPage({
return (
<>
<PageBanner
title="محصولات آراد آریسمان"
title="محصولات آراد اَریسمان"
subtitle="مکمل‌های غذایی، ویتامینه و معدنی برای دام، طیور و زنبور عسل"
breadcrumb="محصولات"
/>
+3 -3
View File
@@ -7,7 +7,7 @@ export default async function About() {
const slotImage = slot?.images?.[0];
const imageSrc = slotImage?.url || "/images/hero-2.jpg";
const imageAlt = slotImage?.titleFa || "محصولات آراد آریسمان";
const imageAlt = slotImage?.titleFa || "محصولات آراد اَریسمان";
const objectPositionClass = slotImage ? "object-center" : "object-left";
const image = (
<Image
@@ -38,10 +38,10 @@ export default async function About() {
<div className="order-1 lg:order-2 text-center lg:text-start">
<span className="text-sm font-bold text-accent">درباره ما</span>
<h2 className="mt-3 text-3xl sm:text-4xl font-extrabold text-primary">
آراد آریسمان
آراد اَریسمان
</h2>
<p className="mt-6 leading-8 text-foreground">
شرکت آراد آریسمان پیشرو در تولید و عرضه افزودنی‌های خوراک، ویتامین‌ها و
شرکت آراد اَریسمان پیشرو در تولید و عرضه افزودنی‌های خوراک، ویتامین‌ها و
مکمل‌های غذایی دام و طیور با بیش از ۲۳ سال فعالیت در بازار ایران می‌باشد.
واردات این شرکت عمدتا از تولیدکنندگان معتبر بین‌المللی غذای دام و طیور از
کشورهای انگلستان، فرانسه، ترکیه، هندوستان و چین می‌باشد.
+71 -56
View File
@@ -1,63 +1,78 @@
const cards = [
{
title: "آدرس ما",
lines: ["قم، شهرک صنعتی شکوهیه، فاز دو،", "خیابان شهید بروجردی، نبش کلاهدوز یک، پلاک ۸۶۶"],
icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M12 22s7-6.3 7-12a7 7 0 1 0-14 0c0 5.7 7 12 7 12Zm0-9a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z"
fill="currentColor"
/>
</svg>
),
},
{
title: "تلفن تماس",
lines: ["09104067935", "۰۲۵۳۳۳۴۲۶۳۳ ، ۰۲۵۳۳۳۴۲۹۶۷ ، ۰۲۵۳۳۳۴۲۹۸۳"],
icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
),
},
{
title: "ساعات کاری",
lines: ["شنبه تا چهارشنبه: ۸ الی ۱۷", "پنجشنبه: ۸ الی ۱۳"],
icon: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm1-10.4 4 2.3-1 1.7-5-2.9V6h2v5.6Z"
fill="currentColor"
/>
</svg>
),
},
];
import {
getResolvedBusinessContact,
phoneTelHref,
type BusinessPhoneNumber,
} from "@/lib/meshkee";
const hoursLines = ["شنبه تا پنجشنبه: ۷ الی ۱۸"];
function phoneLabel(phone: BusinessPhoneNumber): string {
if (phone.type === "cell") return "موبایل";
if (phone.type === "landline") return "تلفن ثابت";
return phone.label?.trim() || "تلفن";
}
export default async function ContactInfo() {
const contact = await getResolvedBusinessContact();
export default function ContactInfo() {
return (
<div className="grid grid-cols-1 sm:grid-cols-3 gap-5">
{cards.map((c) => (
<div
key={c.title}
className="rounded-2xl border border-black/5 bg-white p-7 shadow-sm"
>
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/5 text-primary">
{c.icon}
</div>
<h3 className="mt-4 font-bold text-secondary">{c.title}</h3>
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground" dir={c.title === "تلفن تماس" ? "ltr" : undefined}>
{c.lines.map((line) => (
<p key={line} className={c.title === "تلفن تماس" ? "text-right" : undefined}>
{line}
</p>
))}
</div>
<div className="rounded-2xl border border-black/5 bg-white p-7 shadow-sm">
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/5 text-primary">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M12 22s7-6.3 7-12a7 7 0 1 0-14 0c0 5.7 7 12 7 12Zm0-9a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z"
fill="currentColor"
/>
</svg>
</div>
))}
<h3 className="mt-4 font-bold text-secondary">آدرس ما</h3>
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground">
<p>{contact.address}</p>
</div>
</div>
<div className="rounded-2xl border border-black/5 bg-white p-7 shadow-sm">
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/5 text-primary">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
</div>
<h3 className="mt-4 font-bold text-secondary">تلفن تماس</h3>
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground" dir="ltr">
{contact.phones.map((p) => (
<p key={`${p.type}-${p.number}`} className="text-right">
<span className="text-foreground/70">{phoneLabel(p)}: </span>
<a
href={phoneTelHref(p.number)}
className="hover:text-primary transition-colors"
>
{p.number}
</a>
</p>
))}
</div>
</div>
<div className="rounded-2xl border border-black/5 bg-white p-7 shadow-sm">
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/5 text-primary">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm1-10.4 4 2.3-1 1.7-5-2.9V6h2v5.6Z"
fill="currentColor"
/>
</svg>
</div>
<h3 className="mt-4 font-bold text-secondary">ساعات کاری</h3>
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground">
{hoursLines.map((line) => (
<p key={line}>{line}</p>
))}
</div>
</div>
</div>
);
}
+29 -14
View File
@@ -2,8 +2,7 @@ import Image from "next/image";
import Link from "next/link";
import Container from "./Container";
import MeshkeeCredit from "./MeshkeeCredit";
const phones = ["09104067935", "۰۲۵۳۳۳۴۲۶۳۳", "۰۲۵۳۳۳۴۲۹۶۷", "۰۲۵۳۳۳۴۲۹۸۳"];
import { getResolvedBusinessContact, phoneTelHref } from "@/lib/meshkee";
const quickLinks = [
{ label: "صفحه اصلی", href: "/" },
@@ -13,7 +12,9 @@ const quickLinks = [
{ label: "تماس با ما", href: "/contact" },
];
export default function Footer() {
export default async function Footer() {
const contact = await getResolvedBusinessContact();
return (
<footer id="footer" className="relative bg-secondary text-white/80 overflow-hidden">
<Image
@@ -27,13 +28,13 @@ export default function Footer() {
<div>
<Image
src="/images/footer-logo.png"
alt="آراد آریسمان"
alt="آراد اَریسمان"
width={140}
height={40}
className="h-10 w-auto"
/>
<p className="mt-5 text-sm leading-7 text-white/60">
شرکت آراد آریسمان، پیشرو در تولید و عرضه افزودنی‌های خوراک، ویتامین‌ها و
شرکت آراد اَریسمان، پیشرو در تولید و عرضه افزودنی‌های خوراک، ویتامین‌ها و
مکمل‌های غذایی دام و طیور با بیش از ۲۳ سال تجربه.
</p>
</div>
@@ -53,22 +54,36 @@ export default function Footer() {
<div>
<h4 className="text-white font-bold mb-5">آدرس ما</h4>
<p className="text-sm leading-7 text-white/60">
قم، شهرک صنعتی شکوهیه، فاز دو، خیابان شهید بروجردی، نبش کلاهدوز یک، پلاک ۸۶۶
</p>
<p className="text-sm leading-7 text-white/60">{contact.address}</p>
<h4 className="text-white font-bold mt-6 mb-3">ساعات کاری</h4>
<p className="text-sm leading-7 text-white/60">شنبه تا پنجشنبه: ۷ الی ۱۸</p>
</div>
<div>
<h4 className="text-white font-bold mb-5">راه‌های ارتباطی</h4>
<ul className="space-y-3 text-sm">
{phones.map((p) => (
<li key={p}>
<a href={`tel:${p}`} dir="ltr" className="hover:text-accent transition-colors block text-right">
{p}
{contact.phones.map((p) => (
<li key={`${p.type}-${p.number}`}>
<a
href={phoneTelHref(p.number)}
dir="ltr"
className="hover:text-accent transition-colors block text-start"
>
{p.number}
</a>
</li>
))}
{contact.emails.map((email) => (
<li key={email}>
<a
href={`mailto:${email}`}
className="hover:text-accent transition-colors block"
dir="ltr"
>
{email}
</a>
</li>
))}
<li className="text-white/50">۰۲۵۳۳۳۴۲۹۴۲ (فاکس)</li>
</ul>
</div>
</Container>
@@ -76,7 +91,7 @@ export default function Footer() {
<div className="footer-bottom">
<Container>
<div className="footer-bottom-bar">
<div className="footer-bottom-site">آراد آریسمان</div>
<div className="footer-bottom-site">آراد اَریسمان</div>
<MeshkeeCredit />
</div>
</Container>
+6 -2
View File
@@ -1,12 +1,16 @@
import { getTopLevelCategories } from "@/lib/meshkee";
import { getResolvedBusinessContact, getTopLevelCategories } from "@/lib/meshkee";
import { categoryPath } from "@/lib/urls";
import HeaderNav from "./HeaderNav";
export default async function Header() {
const categories = await getTopLevelCategories();
const [categories, contact] = await Promise.all([
getTopLevelCategories(),
getResolvedBusinessContact(),
]);
return (
<HeaderNav
phoneNumber={contact.primaryPhone?.number ?? ""}
productCategories={categories.map((cat) => ({
id: cat.id,
nameFa: cat.nameFa,
+19 -13
View File
@@ -22,8 +22,10 @@ const navLinks = [
export default function HeaderNav({
productCategories,
phoneNumber,
}: {
productCategories: NavCategory[];
phoneNumber: string;
}) {
const pathname = usePathname();
const [scrolledPast, setScrolledPast] = useState(false);
@@ -84,18 +86,22 @@ export default function HeaderNav({
<header className="fixed inset-x-0 top-0 z-50">
<div className="relative z-[60] bg-secondary text-white">
<Container className="flex h-11 items-center justify-between text-sm">
<a
href="tel:09104067935"
className="flex items-center gap-2 text-white/90 hover:text-accent transition-colors"
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" className="shrink-0">
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
<span dir="ltr">09104067935</span>
</a>
{phoneNumber ? (
<a
href={`tel:${phoneNumber.replace(/[^\d+]/g, "")}`}
className="flex items-center gap-2 text-white/90 hover:text-accent transition-colors"
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" className="shrink-0">
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
<span dir="ltr">{phoneNumber}</span>
</a>
) : (
<span />
)}
<div className="flex items-center gap-4">
<a href="#" aria-label="تلگرام" className="text-white/90 hover:text-accent transition-colors">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none">
@@ -136,7 +142,7 @@ export default function HeaderNav({
<Link href="/" className="shrink-0" onClick={() => setMobileOpen(false)}>
<Image
src={scrolled || mobileOpen ? "/images/logo-wordmark.png" : "/images/footer-logo.png"}
alt="آراد آریسمان"
alt="آراد اَریسمان"
width={140}
height={40}
className="h-10 w-auto"
+2 -2
View File
@@ -9,7 +9,7 @@ export default function Hero() {
<div className="relative w-full aspect-[4/3] lg:aspect-auto lg:h-[480px] rounded-3xl overflow-hidden shadow-xl">
<Image
src="/images/hero-1.jpg"
alt="محصولات آراد آریسمان در مزرعه گندم"
alt="محصولات آراد اَریسمان در مزرعه گندم"
fill
priority
className="object-cover object-left"
@@ -39,7 +39,7 @@ export default function Hero() {
<div className="order-1 lg:order-2 text-center lg:text-start">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold text-primary leading-[1.15]">
آراد آریسمان
آراد اَریسمان
</h1>
<p className="mt-5 text-lg sm:text-xl text-foreground max-w-md mx-auto lg:mx-0">
قدرت رشد، از دل تغذیه سالم
+3 -3
View File
@@ -130,7 +130,7 @@ export default function HeroSlider({
<section
role="region"
aria-roledescription="carousel"
aria-label="اسلایدر معرفی آراد آریسمان"
aria-label="اسلایدر معرفی آراد اَریسمان"
onMouseEnter={pause}
onMouseLeave={resume}
className="relative -mt-[125px] h-svh min-h-[520px] w-full overflow-hidden bg-secondary"
@@ -149,7 +149,7 @@ export default function HeroSlider({
<Link href={slide.linkUrl} className="absolute inset-0 block" aria-label={slide.title || "مشاهده"}>
<Image
src={slide.image}
alt={slide.title || "آراد آریسمان"}
alt={slide.title || "آراد اَریسمان"}
fill
priority={i === 0}
className="object-cover"
@@ -159,7 +159,7 @@ export default function HeroSlider({
) : (
<Image
src={slide.image}
alt={slide.title || "آراد آریسمان"}
alt={slide.title || "آراد اَریسمان"}
fill
priority={i === 0}
className="object-cover"
+20 -14
View File
@@ -1,10 +1,14 @@
import Link from "next/link";
import Container from "./Container";
import ScrollReveal from "./ScrollReveal";
import { getResolvedBusinessContact, phoneTelHref } from "@/lib/meshkee";
export default async function HomeContactStrip() {
const contact = await getResolvedBusinessContact();
const phone = contact.primaryPhone;
export default function HomeContactStrip() {
return (
<section className="bg-[#f1e7d9] text-secondary">
<section className="bg-[#f7f1e8] text-secondary">
<Container>
<ScrollReveal>
<div className="flex flex-col gap-6 py-10 sm:flex-row sm:items-center sm:justify-between sm:py-12">
@@ -16,18 +20,20 @@ export default function HomeContactStrip() {
</div>
<div className="flex flex-wrap items-center gap-4 sm:gap-5 shrink-0">
<a
href="tel:09104067935"
className="inline-flex items-center gap-2 rounded-full border border-primary/20 bg-white/40 px-5 py-3 text-[15px] font-medium text-primary hover:bg-white/70 transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden>
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
<span dir="ltr">09104067935</span>
</a>
{phone ? (
<a
href={phoneTelHref(phone.number)}
className="inline-flex items-center gap-2 rounded-full border border-primary/20 bg-white/40 px-5 py-3 text-[15px] font-medium text-primary hover:bg-white/70 transition-colors"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden>
<path
d="M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .8-.2 1L6.6 10.8z"
fill="currentColor"
/>
</svg>
<span dir="ltr">{phone.number}</span>
</a>
) : null}
<Link
href="/contact"
className="inline-flex items-center justify-center rounded-full bg-primary px-7 py-3 text-[15px] font-bold text-white hover:bg-primary-dark transition-colors"
+1 -1
View File
@@ -18,7 +18,7 @@ export default function ImportCountries() {
واردات از تولیدکنندگان معتبر جهانی
</h2>
<p className="mt-4 text-foreground">
آراد آریسمان محصولات خود را عمدتا از تولیدکنندگان معتبر بین‌المللی
آراد اَریسمان محصولات خود را عمدتا از تولیدکنندگان معتبر بین‌المللی
این کشورها وارد می‌کند
</p>
</div>
+7 -3
View File
@@ -52,9 +52,13 @@ export default function ProductCard({ product }: { product: Product }) {
<p className="mt-2 text-sm text-foreground line-clamp-2">{excerpt}</p>
)}
<div className="mt-3 flex items-center justify-between">
<span className="text-sm font-bold text-primary">
{productPriceLabel(product)}
</span>
{product.store?.minPrice ? (
<span className="text-sm font-bold text-primary">
{productPriceLabel(product)}
</span>
) : (
<span />
)}
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-primary/5 text-primary rotate-180 group-hover:bg-primary group-hover:text-white transition-colors">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none">
<path
+25 -14
View File
@@ -1,14 +1,9 @@
import Image from "next/image";
import Container from "./Container";
const stats = [
{ value: "۲۳۰+", label: "رضایت مشتری" },
{ value: "۲۳", label: "سال تجربه" },
];
export default function Stats() {
return (
<section className="relative py-20 sm:py-28">
<section className="relative py-20 sm:py-28 overflow-hidden">
<Image
src="/images/stats-banner.jpg"
alt=""
@@ -18,15 +13,31 @@ export default function Stats() {
/>
<div className="absolute inset-0 bg-primary-dark/80" />
<Container className="relative">
<div className="grid grid-cols-2 max-w-xl mx-auto text-center gap-8">
{stats.map((s) => (
<div key={s.label}>
<div className="text-4xl sm:text-5xl font-extrabold text-white">
{s.value}
</div>
<div className="mt-3 text-white/80">{s.label}</div>
<div className="flex justify-center text-white">
<div className="inline-flex items-center gap-4 sm:gap-5">
<div className="shrink-0 text-center">
<p className="text-5xl sm:text-7xl md:text-8xl font-extrabold tracking-tight leading-none">
۱۴ سال
</p>
<p
dir="ltr"
className="mt-2 font-display text-xs sm:text-sm font-medium tracking-[0.06em] text-white/75"
>
14 years of experience
</p>
</div>
))}
<div
className="hidden sm:block h-14 sm:h-16 w-px shrink-0 bg-white/35"
aria-hidden
/>
<p className="text-base sm:text-xl md:text-2xl font-medium leading-8 sm:leading-10 text-white/90 text-start">
تولید تخصصی محصولات
<br />
مکمل دام و طیور
</p>
</div>
</div>
</Container>
</section>
+119
View File
@@ -49,6 +49,125 @@ export async function getWebsiteFavicon(): Promise<WebsiteFavicon> {
}
}
/** Public business profile: about, phones, addresses, social (dashboard Business Data). */
export type BusinessPhoneNumber = {
label?: string;
type: "landline" | "cell" | string;
number: string;
};
export type BusinessAddress = {
id: string;
name: string | null;
province: string | null;
city: string | null;
address: string | null;
postalCode: string | null;
landline: string | null;
};
export type BusinessSocialMedia = {
whatsapp?: string;
telegram?: string;
instagram?: string;
linkedin?: string;
youtube?: string;
aparat?: string;
};
export type BusinessInfo = {
id: string;
name: string;
nameFa: string;
about: string;
vision: string;
logoUrl: string | null;
logoDarkUrl: string | null;
faviconUrl: string | null;
emails: string[];
phoneNumbers: BusinessPhoneNumber[];
socialMedia: BusinessSocialMedia;
addresses: BusinessAddress[];
schema?: {
enabled: boolean;
type: string;
jsonLd?: Record<string, unknown> | null;
};
};
const FALLBACK_ADDRESS =
"قم، شهرک صنعتی شکوهیه، فاز دو، خیابان شهید بروجردی، نبش کلاهدوز یک، پلاک ۸۶۶";
const FALLBACK_PHONES: BusinessPhoneNumber[] = [
{ type: "cell", number: "09128540059", label: "Cell" },
{ type: "landline", number: "02533342633", label: "Landline" },
];
export async function getBusinessInfo(): Promise<BusinessInfo | null> {
try {
return await meshkeeFetch<BusinessInfo>(
`/tenants/${TENANT_DOMAIN}/website/business-info`,
300
);
} catch {
return null;
}
}
/** Build a single-line Persian address from a Meshkee address object. */
export function formatBusinessAddress(addr: BusinessAddress | null | undefined): string {
if (!addr) return "";
const parts: string[] = [];
if (addr.province?.trim()) parts.push(addr.province.trim());
if (addr.city?.trim() && addr.city.trim() !== addr.province?.trim()) {
parts.push(addr.city.trim());
}
if (addr.address?.trim()) parts.push(addr.address.trim());
return parts.join("، ");
}
/** ASCII digits for `tel:` / `mailto:` hrefs (accepts Persian digits). */
export function phoneTelHref(number: string): string {
const ascii = number
.replace(/[۰-۹]/g, (d) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(d)))
.replace(/[^\d+]/g, "");
return ascii ? `tel:${ascii}` : "#";
}
export type ResolvedBusinessContact = {
address: string;
phones: BusinessPhoneNumber[];
cells: BusinessPhoneNumber[];
landlines: BusinessPhoneNumber[];
primaryPhone: BusinessPhoneNumber | null;
emails: string[];
socialMedia: BusinessSocialMedia;
};
/** Contact fields for UI — API values when present, stable local fallbacks otherwise. */
export async function getResolvedBusinessContact(): Promise<ResolvedBusinessContact> {
const info = await getBusinessInfo();
const phones =
info?.phoneNumbers?.filter((p) => p.number?.trim()) ?? [];
const resolvedPhones = phones.length > 0 ? phones : FALLBACK_PHONES;
const cells = resolvedPhones.filter((p) => p.type === "cell");
const landlines = resolvedPhones.filter((p) => p.type === "landline");
const primaryPhone = cells[0] ?? landlines[0] ?? resolvedPhones[0] ?? null;
const formatted =
formatBusinessAddress(info?.addresses?.[0]) || FALLBACK_ADDRESS;
return {
address: formatted,
phones: resolvedPhones,
cells,
landlines,
primaryPhone,
emails: info?.emails?.filter(Boolean) ?? [],
socialMedia: info?.socialMedia ?? {},
};
}
/**
* Business-managed image overrides (hero category icons, category tiles,
* feature icons, about photo, brand logos). Each slot has a stable `key`; when a