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:
co-authored by
Cursor
parent
3ffa43641d
commit
e2468a1ba1
@@ -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
|
sharing the same display name under different ids (backend data-entry
|
||||||
artifact). The summary merges by name and links to whichever id holds
|
artifact). The summary merges by name and links to whichever id holds
|
||||||
the most products under that name.
|
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)
|
## Static image slots (business-managed overrides)
|
||||||
|
|
||||||
|
|||||||
+14
@@ -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.
|
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
|
## Other conventions
|
||||||
|
|
||||||
- Category tiles from live products (`getCategorySummary`) because the raw `/categories` taxonomy has duplicate display names.
|
- Category tiles from live products (`getCategorySummary`) because the raw `/categories` taxonomy has duplicate display names.
|
||||||
|
|||||||
+56
-28
@@ -4,36 +4,54 @@ import Link from "next/link";
|
|||||||
import Container from "@/components/Container";
|
import Container from "@/components/Container";
|
||||||
import PageBanner from "@/components/PageBanner";
|
import PageBanner from "@/components/PageBanner";
|
||||||
import MissionVision from "@/components/MissionVision";
|
import MissionVision from "@/components/MissionVision";
|
||||||
import ImportCountries from "@/components/ImportCountries";
|
|
||||||
import Features from "@/components/Features";
|
import Features from "@/components/Features";
|
||||||
import { pageMetadata } from "@/lib/seo";
|
import { pageMetadata } from "@/lib/seo";
|
||||||
|
import {
|
||||||
|
getResolvedBusinessContact,
|
||||||
|
phoneTelHref,
|
||||||
|
} from "@/lib/meshkee";
|
||||||
|
|
||||||
export const metadata: Metadata = pageMetadata({
|
export const metadata: Metadata = pageMetadata({
|
||||||
title: "درباره ما | آراد آریسمان",
|
title: "درباره ما | آراد اَریسمان",
|
||||||
description:
|
description:
|
||||||
"آشنایی با شرکت آراد آریسمان؛ بیش از ۲۳ سال تجربه در تولید و عرضه مکملهای غذایی دام، طیور و زنبور عسل.",
|
"آشنایی با شرکت آراد اَریسمان؛ بیش از ۲۳ سال تجربه در تولید و عرضه مکملهای غذایی دام، طیور و زنبور عسل.",
|
||||||
path: "/about",
|
path: "/about",
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function AboutPage() {
|
export default async function AboutPage() {
|
||||||
|
const contact = await getResolvedBusinessContact();
|
||||||
|
const phone = contact.primaryPhone;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageBanner
|
<PageBanner
|
||||||
title="درباره آراد آریسمان"
|
title="درباره آراد اَریسمان"
|
||||||
subtitle="بیش از دو دهه تجربه در تولید و عرضه مکملهای غذایی دام، طیور و زنبور عسل"
|
subtitle="بیش از دو دهه تجربه در تولید و عرضه مکملهای غذایی دام، طیور و زنبور عسل"
|
||||||
breadcrumb="درباره ما"
|
breadcrumb="درباره ما"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<section className="py-16 sm:py-20">
|
<section className="py-16 sm:py-20">
|
||||||
<Container className="grid grid-cols-1 lg:grid-cols-2 items-center gap-12">
|
<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
|
<Image
|
||||||
src="/images/category-3.jpg"
|
src="/images/stats-banner.jpg"
|
||||||
alt="محصولات آراد آریسمان"
|
alt=""
|
||||||
fill
|
fill
|
||||||
className="object-contain p-6"
|
className="object-cover scale-110 blur-[6px]"
|
||||||
sizes="(min-width: 1024px) 45vw, 90vw"
|
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>
|
||||||
|
|
||||||
<div className="order-1 lg:order-2 text-center lg:text-start">
|
<div className="order-1 lg:order-2 text-center lg:text-start">
|
||||||
@@ -42,7 +60,7 @@ export default function AboutPage() {
|
|||||||
تغذیه مطمئن، پرورش موفق
|
تغذیه مطمئن، پرورش موفق
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-6 leading-8 text-foreground">
|
<p className="mt-6 leading-8 text-foreground">
|
||||||
شرکت آراد آریسمان پیشرو در تولید و عرضه افزودنیهای خوراک، ویتامینها و
|
شرکت آراد اَریسمان پیشرو در تولید و عرضه افزودنیهای خوراک، ویتامینها و
|
||||||
مکملهای غذایی دام و طیور با بیش از ۲۳ سال فعالیت در بازار ایران میباشد.
|
مکملهای غذایی دام و طیور با بیش از ۲۳ سال فعالیت در بازار ایران میباشد.
|
||||||
واردات این شرکت عمدتا از تولیدکنندگان معتبر بینالمللی غذای دام و طیور از
|
واردات این شرکت عمدتا از تولیدکنندگان معتبر بینالمللی غذای دام و طیور از
|
||||||
کشورهای انگلستان، فرانسه، ترکیه، هندوستان و چین میباشد.
|
کشورهای انگلستان، فرانسه، ترکیه، هندوستان و چین میباشد.
|
||||||
@@ -53,18 +71,28 @@ export default function AboutPage() {
|
|||||||
نتیجهی این رویکرد، اعتماد پایدار بیش از ۲۳۰ مشتری در سراسر کشور است.
|
نتیجهی این رویکرد، اعتماد پایدار بیش از ۲۳۰ مشتری در سراسر کشور است.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="mt-8 flex justify-center lg:justify-start gap-10">
|
<div className="mt-8 flex justify-center lg:justify-start">
|
||||||
<div>
|
<div className="inline-flex items-center gap-4 sm:gap-5">
|
||||||
<div className="text-3xl font-extrabold text-primary">۲۳+</div>
|
<div className="shrink-0 text-center lg:text-start">
|
||||||
<div className="mt-1 text-sm text-foreground">سال تجربه</div>
|
<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>
|
||||||
<div>
|
<div
|
||||||
<div className="text-3xl font-extrabold text-primary">۲۳۰+</div>
|
className="hidden sm:block h-12 w-px shrink-0 bg-primary/20"
|
||||||
<div className="mt-1 text-sm text-foreground">رضایت مشتری</div>
|
aria-hidden
|
||||||
</div>
|
/>
|
||||||
<div>
|
<p className="text-sm sm:text-base font-medium leading-7 text-foreground text-start">
|
||||||
<div className="text-3xl font-extrabold text-primary">۵</div>
|
تولید تخصصی محصولات
|
||||||
<div className="mt-1 text-sm text-foreground">کشور واردات</div>
|
<br />
|
||||||
|
مکمل دام و طیور
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -75,16 +103,14 @@ export default function AboutPage() {
|
|||||||
|
|
||||||
<section className="bg-surface">
|
<section className="bg-surface">
|
||||||
<Container className="pt-16 sm:pt-20 text-center max-w-xl mx-auto">
|
<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 className="mt-3 text-3xl sm:text-4xl font-extrabold text-primary">
|
||||||
مزایای مکملهای آراد آریسمان
|
مزایای مکملهای آراد اَریسمان
|
||||||
</h2>
|
</h2>
|
||||||
</Container>
|
</Container>
|
||||||
<Features />
|
<Features />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<ImportCountries />
|
|
||||||
|
|
||||||
<section className="py-16 sm:py-20">
|
<section className="py-16 sm:py-20">
|
||||||
<Container>
|
<Container>
|
||||||
<div className="rounded-3xl bg-primary px-8 py-14 sm:px-16 text-center">
|
<div className="rounded-3xl bg-primary px-8 py-14 sm:px-16 text-center">
|
||||||
@@ -92,7 +118,7 @@ export default function AboutPage() {
|
|||||||
برای مشاوره و خرید محصولات همین حالا با ما در تماس باشید
|
برای مشاوره و خرید محصولات همین حالا با ما در تماس باشید
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-4 text-white/80 max-w-xl mx-auto">
|
<p className="mt-4 text-white/80 max-w-xl mx-auto">
|
||||||
کارشناسان آراد آریسمان آماده پاسخگویی به سوالات شما درباره مکملها و
|
کارشناسان آراد اَریسمان آماده پاسخگویی به سوالات شما درباره مکملها و
|
||||||
نحوه مصرف آنها هستند.
|
نحوه مصرف آنها هستند.
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-8 flex flex-wrap justify-center gap-4">
|
<div className="mt-8 flex flex-wrap justify-center gap-4">
|
||||||
@@ -102,13 +128,15 @@ export default function AboutPage() {
|
|||||||
>
|
>
|
||||||
تماس با ما
|
تماس با ما
|
||||||
</Link>
|
</Link>
|
||||||
|
{phone ? (
|
||||||
<a
|
<a
|
||||||
href="tel:09104067935"
|
href={phoneTelHref(phone.number)}
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
className="rounded-full border border-white/30 px-7 py-3.5 text-white font-semibold hover:bg-white/10 transition-colors"
|
className="rounded-full border border-white/30 px-7 py-3.5 text-white font-semibold hover:bg-white/10 transition-colors"
|
||||||
>
|
>
|
||||||
09104067935
|
{phone.number}
|
||||||
</a>
|
</a>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export async function generateMetadata({
|
|||||||
if (!post) return {};
|
if (!post) return {};
|
||||||
const title = postTitle(post);
|
const title = postTitle(post);
|
||||||
return pageMetadata({
|
return pageMetadata({
|
||||||
title: `${title} | آراد آریسمان`,
|
title: `${title} | آراد اَریسمان`,
|
||||||
description: postExcerpt(post, 160),
|
description: postExcerpt(post, 160),
|
||||||
path: blogPath(post),
|
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 className="mt-10 rounded-2xl bg-surface p-6 flex flex-wrap items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-bold text-secondary">نویسنده: تیم آراد آریسمان</p>
|
<p className="font-bold text-secondary">نویسنده: تیم آراد اَریسمان</p>
|
||||||
<p className="mt-1 text-sm text-foreground">
|
<p className="mt-1 text-sm text-foreground">
|
||||||
برای مشاوره تخصصی تغذیه دام و طیور با ما در تماس باشید.
|
برای مشاوره تخصصی تغذیه دام و طیور با ما در تماس باشید.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import Pagination from "@/components/Pagination";
|
|||||||
import { getPosts } from "@/lib/meshkee";
|
import { getPosts } from "@/lib/meshkee";
|
||||||
|
|
||||||
export const metadata = pageMetadata({
|
export const metadata = pageMetadata({
|
||||||
title: "مقالات | آراد آریسمان",
|
title: "مقالات | آراد اَریسمان",
|
||||||
description:
|
description:
|
||||||
"مقالات آموزشی درباره تغذیه دام، طیور و زنبور عسل از تیم آراد آریسمان.",
|
"مقالات آموزشی درباره تغذیه دام، طیور و زنبور عسل از تیم آراد اَریسمان.",
|
||||||
path: "/blog",
|
path: "/blog",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ export default async function BlogPage({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageBanner
|
<PageBanner
|
||||||
title="مقالات آراد آریسمان"
|
title="مقالات آراد اَریسمان"
|
||||||
subtitle="نکات آموزشی و تخصصی درباره تغذیه دام، طیور و زنبور عسل"
|
subtitle="نکات آموزشی و تخصصی درباره تغذیه دام، طیور و زنبور عسل"
|
||||||
breadcrumb="مقالات"
|
breadcrumb="مقالات"
|
||||||
/>
|
/>
|
||||||
|
|||||||
+47
-12
@@ -3,24 +3,49 @@ import PageBanner from "@/components/PageBanner";
|
|||||||
import ContactInfo from "@/components/ContactInfo";
|
import ContactInfo from "@/components/ContactInfo";
|
||||||
import ContactForm from "@/components/ContactForm";
|
import ContactForm from "@/components/ContactForm";
|
||||||
import { pageMetadata } from "@/lib/seo";
|
import { pageMetadata } from "@/lib/seo";
|
||||||
|
import {
|
||||||
|
getResolvedBusinessContact,
|
||||||
|
phoneTelHref,
|
||||||
|
} from "@/lib/meshkee";
|
||||||
|
|
||||||
export const metadata = pageMetadata({
|
export const metadata = pageMetadata({
|
||||||
title: "تماس با ما | آراد آریسمان",
|
title: "تماس با ما | آراد اَریسمان",
|
||||||
description:
|
description:
|
||||||
"راههای ارتباطی با شرکت آراد آریسمان؛ آدرس، تلفن تماس و فرم ارسال پیام.",
|
"راههای ارتباطی با شرکت آراد اَریسمان؛ آدرس، تلفن تماس و فرم ارسال پیام.",
|
||||||
path: "/contact",
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageBanner
|
<PageBanner
|
||||||
title="تماس با ما"
|
title="تماس با ما"
|
||||||
subtitle="سوالات، پیشنهادات یا درخواست مشاوره خود را برای ما بفرستید؛ کارشناسان آراد آریسمان در اسرع وقت پاسخگوی شما خواهند بود."
|
subtitle="سوالات، پیشنهادات یا درخواست مشاوره خود را برای ما بفرستید؛ کارشناسان آراد اَریسمان در اسرع وقت پاسخگوی شما خواهند بود."
|
||||||
breadcrumb="تماس با ما"
|
breadcrumb="تماس با ما"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -44,8 +69,8 @@ export default function ContactPage() {
|
|||||||
<div className="lg:col-span-2 flex flex-col gap-5">
|
<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">
|
<div className="relative flex-1 min-h-[280px] rounded-2xl overflow-hidden border border-black/5 shadow-sm">
|
||||||
<iframe
|
<iframe
|
||||||
title="نقشه آراد آریسمان"
|
title="نقشه آراد اَریسمان"
|
||||||
src={`https://www.google.com/maps?q=${mapQuery}&output=embed`}
|
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"
|
className="absolute inset-0 h-full w-full border-0"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer-when-downgrade"
|
referrerPolicy="no-referrer-when-downgrade"
|
||||||
@@ -55,8 +80,11 @@ export default function ContactPage() {
|
|||||||
<div className="rounded-2xl bg-secondary p-7 text-white">
|
<div className="rounded-2xl bg-secondary p-7 text-white">
|
||||||
<h3 className="font-bold">ما را در شبکههای اجتماعی دنبال کنید</h3>
|
<h3 className="font-bold">ما را در شبکههای اجتماعی دنبال کنید</h3>
|
||||||
<div className="mt-5 flex items-center gap-4">
|
<div className="mt-5 flex items-center gap-4">
|
||||||
|
{telegram ? (
|
||||||
<a
|
<a
|
||||||
href="#"
|
href={telegramHref(telegram)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
aria-label="تلگرام"
|
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"
|
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
|
||||||
>
|
>
|
||||||
@@ -67,8 +95,12 @@ export default function ContactPage() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
) : null}
|
||||||
|
{whatsapp ? (
|
||||||
<a
|
<a
|
||||||
href="#"
|
href={whatsappHref(whatsapp)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
aria-label="واتساپ"
|
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"
|
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
|
||||||
>
|
>
|
||||||
@@ -79,8 +111,10 @@ export default function ContactPage() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
) : null}
|
||||||
|
{primaryPhone ? (
|
||||||
<a
|
<a
|
||||||
href="tel:09104067935"
|
href={phoneTelHref(primaryPhone.number)}
|
||||||
aria-label="تماس تلفنی"
|
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"
|
className="flex h-10 w-10 items-center justify-center rounded-full bg-white/10 hover:bg-accent hover:text-secondary transition-colors"
|
||||||
>
|
>
|
||||||
@@ -91,6 +125,7 @@ export default function ContactPage() {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-2
@@ -28,11 +28,11 @@ export async function generateMetadata(): Promise<Metadata> {
|
|||||||
return {
|
return {
|
||||||
metadataBase: new URL(SITE_URL),
|
metadataBase: new URL(SITE_URL),
|
||||||
title: {
|
title: {
|
||||||
default: "آراد آریسمان",
|
default: "آراد اَریسمان",
|
||||||
template: "%s",
|
template: "%s",
|
||||||
},
|
},
|
||||||
description:
|
description:
|
||||||
"شرکت آراد آریسمان، تولید و عرضه مکملها، ویتامینها و افزودنیهای خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
|
"شرکت آراد اَریسمان، تولید و عرضه مکملها، ویتامینها و افزودنیهای خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
|
||||||
icons: {
|
icons: {
|
||||||
icon: iconUrl,
|
icon: iconUrl,
|
||||||
shortcut: iconUrl,
|
shortcut: iconUrl,
|
||||||
|
|||||||
+3
-3
@@ -11,9 +11,9 @@ import { categoryPath, resolveCategorySlotHref } from "@/lib/urls";
|
|||||||
import { pageMetadata } from "@/lib/seo";
|
import { pageMetadata } from "@/lib/seo";
|
||||||
|
|
||||||
export const metadata: Metadata = pageMetadata({
|
export const metadata: Metadata = pageMetadata({
|
||||||
title: "آراد آریسمان | صفحه اصلی",
|
title: "آراد اَریسمان | صفحه اصلی",
|
||||||
description:
|
description:
|
||||||
"شرکت آراد آریسمان، تولید و عرضه مکملها، ویتامینها و افزودنیهای خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
|
"شرکت آراد اَریسمان، تولید و عرضه مکملها، ویتامینها و افزودنیهای خوراک دام و طیور با بیش از ۲۳ سال تجربه.",
|
||||||
path: "/",
|
path: "/",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ export default async function Home() {
|
|||||||
<HomeContactStrip />
|
<HomeContactStrip />
|
||||||
<CategoryProducts
|
<CategoryProducts
|
||||||
categoryNameEn="Poultry"
|
categoryNameEn="Poultry"
|
||||||
className="py-14 sm:py-16"
|
className="py-14 sm:py-16 bg-[#fbf8f3]"
|
||||||
/>
|
/>
|
||||||
<Features />
|
<Features />
|
||||||
<Stats />
|
<Stats />
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import {
|
|||||||
getCategoryAncestors,
|
getCategoryAncestors,
|
||||||
getProductById,
|
getProductById,
|
||||||
getProducts,
|
getProducts,
|
||||||
|
getResolvedBusinessContact,
|
||||||
|
phoneTelHref,
|
||||||
productCatalog,
|
productCatalog,
|
||||||
productImages,
|
productImages,
|
||||||
productPriceLabel,
|
productPriceLabel,
|
||||||
@@ -33,7 +35,7 @@ export async function generateMetadata({
|
|||||||
if (!product) return {};
|
if (!product) return {};
|
||||||
const description = product.summary || stripHtml(product.descriptionHtml, 160);
|
const description = product.summary || stripHtml(product.descriptionHtml, 160);
|
||||||
return pageMetadata({
|
return pageMetadata({
|
||||||
title: `${product.nameFa} | آراد آریسمان`,
|
title: `${product.nameFa} | آراد اَریسمان`,
|
||||||
description,
|
description,
|
||||||
path: productPath(product),
|
path: productPath(product),
|
||||||
});
|
});
|
||||||
@@ -58,7 +60,11 @@ export default async function ProductDetailPage({
|
|||||||
const catalog = productCatalog(product);
|
const catalog = productCatalog(product);
|
||||||
const shortDesc = product.summary || stripHtml(product.descriptionHtml, 160);
|
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
|
const categoryTrail = product.categoryId
|
||||||
? getCategoryAncestors(product.categoryId, allCategories)
|
? getCategoryAncestors(product.categoryId, allCategories)
|
||||||
: [];
|
: [];
|
||||||
@@ -121,13 +127,15 @@ export default async function ProductDetailPage({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 flex flex-wrap gap-3">
|
<div className="mt-6 flex flex-wrap gap-3">
|
||||||
|
{phone ? (
|
||||||
<a
|
<a
|
||||||
href="tel:09104067935"
|
href={phoneTelHref(phone.number)}
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
className="rounded-full bg-primary px-7 py-3.5 text-white font-semibold hover:bg-primary-dark transition-colors"
|
className="rounded-full bg-primary px-7 py-3.5 text-white font-semibold hover:bg-primary-dark transition-colors"
|
||||||
>
|
>
|
||||||
09104067935
|
{phone.number}
|
||||||
</a>
|
</a>
|
||||||
|
) : null}
|
||||||
<Link
|
<Link
|
||||||
href="/contact"
|
href="/contact"
|
||||||
className="rounded-full border border-primary/30 px-7 py-3.5 text-primary font-semibold hover:bg-primary/5 transition-colors"
|
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);
|
const category = await getCategoryById(id);
|
||||||
if (!category) return {};
|
if (!category) return {};
|
||||||
return pageMetadata({
|
return pageMetadata({
|
||||||
title: `${category.nameFa} | محصولات آراد آریسمان`,
|
title: `${category.nameFa} | محصولات آراد اَریسمان`,
|
||||||
description: `مشاهده محصولات دسته ${category.nameFa}؛ مکملهای غذایی آراد آریسمان.`,
|
description: `مشاهده محصولات دسته ${category.nameFa}؛ مکملهای غذایی آراد اَریسمان.`,
|
||||||
path: categoryPath(category),
|
path: categoryPath(category),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import { categoryPath } from "@/lib/urls";
|
|||||||
import { slugifyFa } from "@/lib/slugify";
|
import { slugifyFa } from "@/lib/slugify";
|
||||||
|
|
||||||
export const metadata = pageMetadata({
|
export const metadata = pageMetadata({
|
||||||
title: "محصولات | آراد آریسمان",
|
title: "محصولات | آراد اَریسمان",
|
||||||
description:
|
description:
|
||||||
"مکملهای غذایی، ویتامینه و معدنی دام، طیور و زنبور عسل؛ محصولات آراد آریسمان را مشاهده کنید.",
|
"مکملهای غذایی، ویتامینه و معدنی دام، طیور و زنبور عسل؛ محصولات آراد اَریسمان را مشاهده کنید.",
|
||||||
path: "/products",
|
path: "/products",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export default async function ProductsPage({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageBanner
|
<PageBanner
|
||||||
title="محصولات آراد آریسمان"
|
title="محصولات آراد اَریسمان"
|
||||||
subtitle="مکملهای غذایی، ویتامینه و معدنی برای دام، طیور و زنبور عسل"
|
subtitle="مکملهای غذایی، ویتامینه و معدنی برای دام، طیور و زنبور عسل"
|
||||||
breadcrumb="محصولات"
|
breadcrumb="محصولات"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default async function About() {
|
|||||||
const slotImage = slot?.images?.[0];
|
const slotImage = slot?.images?.[0];
|
||||||
|
|
||||||
const imageSrc = slotImage?.url || "/images/hero-2.jpg";
|
const imageSrc = slotImage?.url || "/images/hero-2.jpg";
|
||||||
const imageAlt = slotImage?.titleFa || "محصولات آراد آریسمان";
|
const imageAlt = slotImage?.titleFa || "محصولات آراد اَریسمان";
|
||||||
const objectPositionClass = slotImage ? "object-center" : "object-left";
|
const objectPositionClass = slotImage ? "object-center" : "object-left";
|
||||||
const image = (
|
const image = (
|
||||||
<Image
|
<Image
|
||||||
@@ -38,10 +38,10 @@ export default async function About() {
|
|||||||
<div className="order-1 lg:order-2 text-center lg:text-start">
|
<div className="order-1 lg:order-2 text-center lg:text-start">
|
||||||
<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 className="mt-3 text-3xl sm:text-4xl font-extrabold text-primary">
|
||||||
آراد آریسمان
|
آراد اَریسمان
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-6 leading-8 text-foreground">
|
<p className="mt-6 leading-8 text-foreground">
|
||||||
شرکت آراد آریسمان پیشرو در تولید و عرضه افزودنیهای خوراک، ویتامینها و
|
شرکت آراد اَریسمان پیشرو در تولید و عرضه افزودنیهای خوراک، ویتامینها و
|
||||||
مکملهای غذایی دام و طیور با بیش از ۲۳ سال فعالیت در بازار ایران میباشد.
|
مکملهای غذایی دام و طیور با بیش از ۲۳ سال فعالیت در بازار ایران میباشد.
|
||||||
واردات این شرکت عمدتا از تولیدکنندگان معتبر بینالمللی غذای دام و طیور از
|
واردات این شرکت عمدتا از تولیدکنندگان معتبر بینالمللی غذای دام و طیور از
|
||||||
کشورهای انگلستان، فرانسه، ترکیه، هندوستان و چین میباشد.
|
کشورهای انگلستان، فرانسه، ترکیه، هندوستان و چین میباشد.
|
||||||
|
|||||||
@@ -1,63 +1,78 @@
|
|||||||
const cards = [
|
import {
|
||||||
{
|
getResolvedBusinessContact,
|
||||||
title: "آدرس ما",
|
phoneTelHref,
|
||||||
lines: ["قم، شهرک صنعتی شکوهیه، فاز دو،", "خیابان شهید بروجردی، نبش کلاهدوز یک، پلاک ۸۶۶"],
|
type BusinessPhoneNumber,
|
||||||
icon: (
|
} 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();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-5">
|
||||||
|
<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">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||||
<path
|
<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"
|
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"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
</div>
|
||||||
},
|
<h3 className="mt-4 font-bold text-secondary">آدرس ما</h3>
|
||||||
{
|
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground">
|
||||||
title: "تلفن تماس",
|
<p>{contact.address}</p>
|
||||||
lines: ["09104067935", "۰۲۵۳۳۳۴۲۶۳۳ ، ۰۲۵۳۳۳۴۲۹۶۷ ، ۰۲۵۳۳۳۴۲۹۸۳"],
|
</div>
|
||||||
icon: (
|
</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">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||||
<path
|
<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"
|
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"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</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">
|
||||||
title: "ساعات کاری",
|
{contact.phones.map((p) => (
|
||||||
lines: ["شنبه تا چهارشنبه: ۸ الی ۱۷", "پنجشنبه: ۸ الی ۱۳"],
|
<p key={`${p.type}-${p.number}`} className="text-right">
|
||||||
icon: (
|
<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">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||||
<path
|
<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"
|
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"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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>
|
</div>
|
||||||
<h3 className="mt-4 font-bold text-secondary">{c.title}</h3>
|
<h3 className="mt-4 font-bold text-secondary">ساعات کاری</h3>
|
||||||
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground" dir={c.title === "تلفن تماس" ? "ltr" : undefined}>
|
<div className="mt-2 space-y-1 text-sm leading-7 text-foreground">
|
||||||
{c.lines.map((line) => (
|
{hoursLines.map((line) => (
|
||||||
<p key={line} className={c.title === "تلفن تماس" ? "text-right" : undefined}>
|
<p key={line}>{line}</p>
|
||||||
{line}
|
|
||||||
</p>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-14
@@ -2,8 +2,7 @@ import Image from "next/image";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Container from "./Container";
|
import Container from "./Container";
|
||||||
import MeshkeeCredit from "./MeshkeeCredit";
|
import MeshkeeCredit from "./MeshkeeCredit";
|
||||||
|
import { getResolvedBusinessContact, phoneTelHref } from "@/lib/meshkee";
|
||||||
const phones = ["09104067935", "۰۲۵۳۳۳۴۲۶۳۳", "۰۲۵۳۳۳۴۲۹۶۷", "۰۲۵۳۳۳۴۲۹۸۳"];
|
|
||||||
|
|
||||||
const quickLinks = [
|
const quickLinks = [
|
||||||
{ label: "صفحه اصلی", href: "/" },
|
{ label: "صفحه اصلی", href: "/" },
|
||||||
@@ -13,7 +12,9 @@ const quickLinks = [
|
|||||||
{ label: "تماس با ما", href: "/contact" },
|
{ label: "تماس با ما", href: "/contact" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Footer() {
|
export default async function Footer() {
|
||||||
|
const contact = await getResolvedBusinessContact();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer id="footer" className="relative bg-secondary text-white/80 overflow-hidden">
|
<footer id="footer" className="relative bg-secondary text-white/80 overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
@@ -27,13 +28,13 @@ export default function Footer() {
|
|||||||
<div>
|
<div>
|
||||||
<Image
|
<Image
|
||||||
src="/images/footer-logo.png"
|
src="/images/footer-logo.png"
|
||||||
alt="آراد آریسمان"
|
alt="آراد اَریسمان"
|
||||||
width={140}
|
width={140}
|
||||||
height={40}
|
height={40}
|
||||||
className="h-10 w-auto"
|
className="h-10 w-auto"
|
||||||
/>
|
/>
|
||||||
<p className="mt-5 text-sm leading-7 text-white/60">
|
<p className="mt-5 text-sm leading-7 text-white/60">
|
||||||
شرکت آراد آریسمان، پیشرو در تولید و عرضه افزودنیهای خوراک، ویتامینها و
|
شرکت آراد اَریسمان، پیشرو در تولید و عرضه افزودنیهای خوراک، ویتامینها و
|
||||||
مکملهای غذایی دام و طیور با بیش از ۲۳ سال تجربه.
|
مکملهای غذایی دام و طیور با بیش از ۲۳ سال تجربه.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,22 +54,36 @@ export default function Footer() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-white font-bold mb-5">آدرس ما</h4>
|
<h4 className="text-white font-bold mb-5">آدرس ما</h4>
|
||||||
<p className="text-sm leading-7 text-white/60">
|
<p className="text-sm leading-7 text-white/60">{contact.address}</p>
|
||||||
قم، شهرک صنعتی شکوهیه، فاز دو، خیابان شهید بروجردی، نبش کلاهدوز یک، پلاک ۸۶۶
|
<h4 className="text-white font-bold mt-6 mb-3">ساعات کاری</h4>
|
||||||
</p>
|
<p className="text-sm leading-7 text-white/60">شنبه تا پنجشنبه: ۷ الی ۱۸</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-white font-bold mb-5">راههای ارتباطی</h4>
|
<h4 className="text-white font-bold mb-5">راههای ارتباطی</h4>
|
||||||
<ul className="space-y-3 text-sm">
|
<ul className="space-y-3 text-sm">
|
||||||
{phones.map((p) => (
|
{contact.phones.map((p) => (
|
||||||
<li key={p}>
|
<li key={`${p.type}-${p.number}`}>
|
||||||
<a href={`tel:${p}`} dir="ltr" className="hover:text-accent transition-colors block text-right">
|
<a
|
||||||
{p}
|
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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
<li className="text-white/50">۰۲۵۳۳۳۴۲۹۴۲ (فاکس)</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
@@ -76,7 +91,7 @@ export default function Footer() {
|
|||||||
<div className="footer-bottom">
|
<div className="footer-bottom">
|
||||||
<Container>
|
<Container>
|
||||||
<div className="footer-bottom-bar">
|
<div className="footer-bottom-bar">
|
||||||
<div className="footer-bottom-site">آراد آریسمان</div>
|
<div className="footer-bottom-site">آراد اَریسمان</div>
|
||||||
<MeshkeeCredit />
|
<MeshkeeCredit />
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { getTopLevelCategories } from "@/lib/meshkee";
|
import { getResolvedBusinessContact, getTopLevelCategories } from "@/lib/meshkee";
|
||||||
import { categoryPath } from "@/lib/urls";
|
import { categoryPath } from "@/lib/urls";
|
||||||
import HeaderNav from "./HeaderNav";
|
import HeaderNav from "./HeaderNav";
|
||||||
|
|
||||||
export default async function Header() {
|
export default async function Header() {
|
||||||
const categories = await getTopLevelCategories();
|
const [categories, contact] = await Promise.all([
|
||||||
|
getTopLevelCategories(),
|
||||||
|
getResolvedBusinessContact(),
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderNav
|
<HeaderNav
|
||||||
|
phoneNumber={contact.primaryPhone?.number ?? ""}
|
||||||
productCategories={categories.map((cat) => ({
|
productCategories={categories.map((cat) => ({
|
||||||
id: cat.id,
|
id: cat.id,
|
||||||
nameFa: cat.nameFa,
|
nameFa: cat.nameFa,
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ const navLinks = [
|
|||||||
|
|
||||||
export default function HeaderNav({
|
export default function HeaderNav({
|
||||||
productCategories,
|
productCategories,
|
||||||
|
phoneNumber,
|
||||||
}: {
|
}: {
|
||||||
productCategories: NavCategory[];
|
productCategories: NavCategory[];
|
||||||
|
phoneNumber: string;
|
||||||
}) {
|
}) {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const [scrolledPast, setScrolledPast] = useState(false);
|
const [scrolledPast, setScrolledPast] = useState(false);
|
||||||
@@ -84,8 +86,9 @@ export default function HeaderNav({
|
|||||||
<header className="fixed inset-x-0 top-0 z-50">
|
<header className="fixed inset-x-0 top-0 z-50">
|
||||||
<div className="relative z-[60] bg-secondary text-white">
|
<div className="relative z-[60] bg-secondary text-white">
|
||||||
<Container className="flex h-11 items-center justify-between text-sm">
|
<Container className="flex h-11 items-center justify-between text-sm">
|
||||||
|
{phoneNumber ? (
|
||||||
<a
|
<a
|
||||||
href="tel:09104067935"
|
href={`tel:${phoneNumber.replace(/[^\d+]/g, "")}`}
|
||||||
className="flex items-center gap-2 text-white/90 hover:text-accent transition-colors"
|
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">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" className="shrink-0">
|
||||||
@@ -94,8 +97,11 @@ export default function HeaderNav({
|
|||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span dir="ltr">09104067935</span>
|
<span dir="ltr">{phoneNumber}</span>
|
||||||
</a>
|
</a>
|
||||||
|
) : (
|
||||||
|
<span />
|
||||||
|
)}
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<a href="#" aria-label="تلگرام" className="text-white/90 hover:text-accent transition-colors">
|
<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">
|
<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)}>
|
<Link href="/" className="shrink-0" onClick={() => setMobileOpen(false)}>
|
||||||
<Image
|
<Image
|
||||||
src={scrolled || mobileOpen ? "/images/logo-wordmark.png" : "/images/footer-logo.png"}
|
src={scrolled || mobileOpen ? "/images/logo-wordmark.png" : "/images/footer-logo.png"}
|
||||||
alt="آراد آریسمان"
|
alt="آراد اَریسمان"
|
||||||
width={140}
|
width={140}
|
||||||
height={40}
|
height={40}
|
||||||
className="h-10 w-auto"
|
className="h-10 w-auto"
|
||||||
|
|||||||
@@ -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">
|
<div className="relative w-full aspect-[4/3] lg:aspect-auto lg:h-[480px] rounded-3xl overflow-hidden shadow-xl">
|
||||||
<Image
|
<Image
|
||||||
src="/images/hero-1.jpg"
|
src="/images/hero-1.jpg"
|
||||||
alt="محصولات آراد آریسمان در مزرعه گندم"
|
alt="محصولات آراد اَریسمان در مزرعه گندم"
|
||||||
fill
|
fill
|
||||||
priority
|
priority
|
||||||
className="object-cover object-left"
|
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">
|
<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 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold text-primary leading-[1.15]">
|
||||||
آراد آریسمان
|
آراد اَریسمان
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-5 text-lg sm:text-xl text-foreground max-w-md mx-auto lg:mx-0">
|
<p className="mt-5 text-lg sm:text-xl text-foreground max-w-md mx-auto lg:mx-0">
|
||||||
قدرت رشد، از دل تغذیه سالم
|
قدرت رشد، از دل تغذیه سالم
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export default function HeroSlider({
|
|||||||
<section
|
<section
|
||||||
role="region"
|
role="region"
|
||||||
aria-roledescription="carousel"
|
aria-roledescription="carousel"
|
||||||
aria-label="اسلایدر معرفی آراد آریسمان"
|
aria-label="اسلایدر معرفی آراد اَریسمان"
|
||||||
onMouseEnter={pause}
|
onMouseEnter={pause}
|
||||||
onMouseLeave={resume}
|
onMouseLeave={resume}
|
||||||
className="relative -mt-[125px] h-svh min-h-[520px] w-full overflow-hidden bg-secondary"
|
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 || "مشاهده"}>
|
<Link href={slide.linkUrl} className="absolute inset-0 block" aria-label={slide.title || "مشاهده"}>
|
||||||
<Image
|
<Image
|
||||||
src={slide.image}
|
src={slide.image}
|
||||||
alt={slide.title || "آراد آریسمان"}
|
alt={slide.title || "آراد اَریسمان"}
|
||||||
fill
|
fill
|
||||||
priority={i === 0}
|
priority={i === 0}
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
@@ -159,7 +159,7 @@ export default function HeroSlider({
|
|||||||
) : (
|
) : (
|
||||||
<Image
|
<Image
|
||||||
src={slide.image}
|
src={slide.image}
|
||||||
alt={slide.title || "آراد آریسمان"}
|
alt={slide.title || "آراد اَریسمان"}
|
||||||
fill
|
fill
|
||||||
priority={i === 0}
|
priority={i === 0}
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Container from "./Container";
|
import Container from "./Container";
|
||||||
import ScrollReveal from "./ScrollReveal";
|
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 (
|
return (
|
||||||
<section className="bg-[#f1e7d9] text-secondary">
|
<section className="bg-[#f7f1e8] text-secondary">
|
||||||
<Container>
|
<Container>
|
||||||
<ScrollReveal>
|
<ScrollReveal>
|
||||||
<div className="flex flex-col gap-6 py-10 sm:flex-row sm:items-center sm:justify-between sm:py-12">
|
<div className="flex flex-col gap-6 py-10 sm:flex-row sm:items-center sm:justify-between sm:py-12">
|
||||||
@@ -16,8 +20,9 @@ export default function HomeContactStrip() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-4 sm:gap-5 shrink-0">
|
<div className="flex flex-wrap items-center gap-4 sm:gap-5 shrink-0">
|
||||||
|
{phone ? (
|
||||||
<a
|
<a
|
||||||
href="tel:09104067935"
|
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"
|
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>
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden>
|
||||||
@@ -26,8 +31,9 @@ export default function HomeContactStrip() {
|
|||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span dir="ltr">09104067935</span>
|
<span dir="ltr">{phone.number}</span>
|
||||||
</a>
|
</a>
|
||||||
|
) : null}
|
||||||
<Link
|
<Link
|
||||||
href="/contact"
|
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"
|
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"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function ImportCountries() {
|
|||||||
واردات از تولیدکنندگان معتبر جهانی
|
واردات از تولیدکنندگان معتبر جهانی
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-4 text-foreground">
|
<p className="mt-4 text-foreground">
|
||||||
آراد آریسمان محصولات خود را عمدتا از تولیدکنندگان معتبر بینالمللی
|
آراد اَریسمان محصولات خود را عمدتا از تولیدکنندگان معتبر بینالمللی
|
||||||
این کشورها وارد میکند
|
این کشورها وارد میکند
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -52,9 +52,13 @@ export default function ProductCard({ product }: { product: Product }) {
|
|||||||
<p className="mt-2 text-sm text-foreground line-clamp-2">{excerpt}</p>
|
<p className="mt-2 text-sm text-foreground line-clamp-2">{excerpt}</p>
|
||||||
)}
|
)}
|
||||||
<div className="mt-3 flex items-center justify-between">
|
<div className="mt-3 flex items-center justify-between">
|
||||||
|
{product.store?.minPrice ? (
|
||||||
<span className="text-sm font-bold text-primary">
|
<span className="text-sm font-bold text-primary">
|
||||||
{productPriceLabel(product)}
|
{productPriceLabel(product)}
|
||||||
</span>
|
</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">
|
<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">
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none">
|
||||||
<path
|
<path
|
||||||
|
|||||||
+24
-13
@@ -1,14 +1,9 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Container from "./Container";
|
import Container from "./Container";
|
||||||
|
|
||||||
const stats = [
|
|
||||||
{ value: "۲۳۰+", label: "رضایت مشتری" },
|
|
||||||
{ value: "۲۳", label: "سال تجربه" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Stats() {
|
export default function Stats() {
|
||||||
return (
|
return (
|
||||||
<section className="relative py-20 sm:py-28">
|
<section className="relative py-20 sm:py-28 overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src="/images/stats-banner.jpg"
|
src="/images/stats-banner.jpg"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -18,15 +13,31 @@ export default function Stats() {
|
|||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-primary-dark/80" />
|
<div className="absolute inset-0 bg-primary-dark/80" />
|
||||||
<Container className="relative">
|
<Container className="relative">
|
||||||
<div className="grid grid-cols-2 max-w-xl mx-auto text-center gap-8">
|
<div className="flex justify-center text-white">
|
||||||
{stats.map((s) => (
|
<div className="inline-flex items-center gap-4 sm:gap-5">
|
||||||
<div key={s.label}>
|
<div className="shrink-0 text-center">
|
||||||
<div className="text-4xl sm:text-5xl font-extrabold text-white">
|
<p className="text-5xl sm:text-7xl md:text-8xl font-extrabold tracking-tight leading-none">
|
||||||
{s.value}
|
۱۴ سال
|
||||||
|
</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>
|
||||||
<div className="mt-3 text-white/80">{s.label}</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>
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -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,
|
* Business-managed image overrides (hero category icons, category tiles,
|
||||||
* feature icons, about photo, brand logos). Each slot has a stable `key`; when a
|
* feature icons, about photo, brand logos). Each slot has a stable `key`; when a
|
||||||
|
|||||||
Reference in New Issue
Block a user