Moshavereh sazmani

This commit is contained in:
2026-02-19 17:56:02 +03:30
parent 21390bd024
commit b39e261ebf
12 changed files with 1265 additions and 531 deletions
+82
View File
@@ -0,0 +1,82 @@
import { NextResponse } from 'next/server'
const TELEGRAM_API = 'https://api.telegram.org'
export interface ConsultingRequestBody {
fullName: string
organization: string
phone: string
area: string
description?: string
}
function escapeForTelegram(text: string): string {
return text
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
}
export async function POST(request: Request) {
const token = process.env.TELEGRAM_BOT_TOKEN
const chatId = process.env.TELEGRAM_CHAT_ID
if (!token || !chatId) {
return NextResponse.json(
{ error: 'تلگرام پیکربندی نشده است. TELEGRAM_BOT_TOKEN و TELEGRAM_CHAT_ID را در .env.local تنظیم کنید.' },
{ status: 500 }
)
}
let body: ConsultingRequestBody
try {
body = await request.json()
} catch {
return NextResponse.json({ error: 'بدنه درخواست نامعتبر است' }, { status: 400 })
}
const { fullName, organization, phone, area, description } = body
if (!fullName?.trim() || !organization?.trim() || !phone?.trim() || !area?.trim()) {
return NextResponse.json({ error: 'فیلدهای الزامی خالی است' }, { status: 400 })
}
const lines = [
'📩 <b>درخواست جدید مشاوره سازمانی</b>',
'',
`<b>نام و نام خانوادگی:</b> ${escapeForTelegram(fullName.trim())}`,
`<b>نام سازمان:</b> ${escapeForTelegram(organization.trim())}`,
`<b>شماره تماس:</b> ${escapeForTelegram(phone.trim())}`,
`<b>حوزه مشاوره:</b> ${escapeForTelegram(area.trim())}`,
]
if (description?.trim()) {
lines.push('', `<b>توضیحات:</b>`, escapeForTelegram(description.trim()))
}
const text = lines.join('\n')
try {
const res = await fetch(`${TELEGRAM_API}/bot${token}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
text,
parse_mode: 'HTML',
}),
})
const data = await res.json().catch(() => ({}))
if (!res.ok) {
return NextResponse.json(
{ error: data.description || 'ارسال به تلگرام ناموفق بود' },
{ status: 502 }
)
}
return NextResponse.json({ ok: true })
} catch (err) {
return NextResponse.json(
{ error: 'خطا در ارتباط با تلگرام' },
{ status: 502 }
)
}
}
+292
View File
@@ -0,0 +1,292 @@
import { AspectRatio } from '@/components/ui/aspect-ratio'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion'
import { ConsultingForm } from '@/components/consulting-form'
import {
Plug2,
Sparkles,
Database,
Gauge,
Shield,
Layout,
BarChart3,
HelpCircle,
} from 'lucide-react'
import Link from 'next/link'
const consultants = [
{
name: 'مشاور ارشد اینتگریشن',
expertise: ['اینتگریشن سیستم‌ها', 'API', 'اتوماسیون'],
description:
'بیش از ده سال تجربه در طراحی و پیاده‌سازی راهکارهای یکپارچه‌سازی برای سازمان‌های بزرگ.',
image: '/assets/logo.svg',
fallback: 'م۱',
},
{
name: 'مشاور هوشمندسازی و RAG',
expertise: ['RAG', 'هوش مصنوعی', 'پردازش زبان طبیعی'],
description:
'تخصص در طراحی سامانه‌های مبتنی بر دانش و هوشمندسازی فرآیندهای سازمانی.',
image: '/assets/logo.svg',
fallback: 'م۲',
},
{
name: 'مشاور عملکرد و معماری',
expertise: ['Performance', 'معماری نرم‌افزار', 'مقیاس‌پذیری'],
description:
'بهینه‌سازی عملکرد سامانه‌ها و طراحی معماری مقیاس‌پذیر و پایدار.',
image: '/assets/logo.svg',
fallback: 'م۳',
},
]
const domains = [
{
title: 'اینتگریشن',
description: 'اتصال سیستم‌ها، APIها و یکپارچه‌سازی داده‌ها و فرآیندها',
icon: Plug2,
},
{
title: 'هوشمندسازی',
description: 'اتوماسیون و هوشمندسازی فرآیندهای کسب‌وکار',
icon: Sparkles,
},
{
title: 'RAG',
description: 'سامانه‌های بازیابی و تولید پاسخ مبتنی بر دانش',
icon: Database,
},
{
title: 'Performance',
description: 'بهینه‌سازی عملکرد، مقیاس‌پذیری و پاسخگویی',
icon: Gauge,
},
{
title: 'امنیت',
description: 'امنیت داده، احراز هویت و کنترل دسترسی',
icon: Shield,
},
{
title: 'معماری نرم‌افزار',
description: 'طراحی معماری، میکروسرویس و طراحی سیستم',
icon: Layout,
},
{
title: 'داده و تحلیل',
description: 'تحلیل داده، گزارش‌گیری و دشبوردهای تحلیلی',
icon: BarChart3,
},
]
const faqItems = [
{
id: 'faq-1',
question: 'مشاوره سازمانی چیست؟',
answer:
'مشاوره سازمانی خدمتی است که در آن متخصصان با بررسی وضعیت فعلی سازمان، چالش‌ها و اهداف شما، راهکارهای فنی و فرآیندی پیشنهاد می‌دهند. این مشاوره می‌تواند در حوزه‌های اینتگریشن، هوشمندسازی، RAG، بهینه‌سازی عملکرد و معماری نرم‌افزار باشد.',
},
{
id: 'faq-2',
question: 'چه زمانی می‌توانم انتظار تماس داشته باشم؟',
answer:
'پس از ثبت درخواست، تیم ما در سریع‌ترین زمان ممکن (معمولاً حداکثر ۲۴ تا ۴۸ ساعت کاری) با شما تماس می‌گیرد تا نیازتان را دقیق‌تر بررسی کنیم و زمان جلسه مشاوره را هماهنگ کنیم.',
},
{
id: 'faq-3',
question: 'آیا مشاوره اولیه رایگان است؟',
answer:
'جلسه اول شناخت و تعیین scope معمولاً به صورت رایگان یا با هزینه نمادین انجام می‌شود. جزئیات بسته به نوع درخواست و حجم کار در اولین تماس به شما اعلام می‌شود.',
},
{
id: 'faq-4',
question: 'برای چه اندازه‌ای از سازمان‌ها مناسب است؟',
answer:
'خدمات مشاوره ما برای استارتاپ‌ها، شرکت‌های کوچک و متوسط و سازمان‌های بزرگ طراحی شده است. محتوای جلسات و پیشنهادها متناسب با اندازه و نیاز هر سازمان تنظیم می‌شود.',
},
]
export const metadata = {
title: 'مشاوره سازمانی | فیپ',
description:
'مشاوره تخصصی در حوزه اینتگریشن، هوشمندسازی، RAG، Performance و معماری نرم‌افزار. در سریع‌ترین زمان با شما تماس می‌گیریم.',
}
export default function ConsultingPage() {
return (
<>
{/* Section 1: Hero - مشاوره سازمانی */}
<section className="bg-background pt-28 pb-16 md:pt-36 md:pb-24">
<div className="mx-auto max-w-6xl px-4 md:px-6">
<div className="grid gap-12 lg:grid-cols-2 lg:gap-16 items-center">
<div className="space-y-8 order-2 lg:order-1">
<div className="space-y-4">
<h1 className="text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl">
مشاوره سازمانی
</h1>
<p className="text-lg text-muted-foreground leading-relaxed max-w-xl">
مشاوره سازمانی به معنای همراهی تخصصی با سازمان شما برای شناسایی چالش‌ها،
انتخاب راهکارهای فنی مناسب و برنامه‌ریزی برای پیاده‌سازی است. ما در حوزه‌های
اینتگریشن، هوشمندسازی، RAG و بهینه‌سازی عملکرد در کنار شما هستیم.
</p>
<p className="text-muted-foreground leading-relaxed max-w-xl">
شرایط همکاری: پس از ثبت درخواست، تیم ما با شما تماس می‌گیرد؛ جلسه اول برای
شناخت نیازها و تعیین دامنه کار است و در ادامه پیشنهاد و برنامه اجرا ارائه
می‌شود.
</p>
</div>
<div className="flex flex-wrap gap-3">
<Button asChild size="lg">
<Link href="#consulting-form">ثبت درخواست مشاوره</Link>
</Button>
<Button asChild variant="outline" size="lg">
<Link href="#domains">حوزه‌های مشاوره</Link>
</Button>
</div>
</div>
<div className="relative order-1 lg:order-2">
<div className="grid gap-4">
<AspectRatio ratio={4 / 3} className="overflow-hidden rounded-2xl bg-muted">
<div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-primary/10 to-primary/5">
<HelpCircle className="size-24 text-primary/40" />
</div>
</AspectRatio>
<AspectRatio ratio={16 / 9} className="overflow-hidden rounded-2xl bg-muted -mt-8 mr-8 border shadow-lg">
<div className="flex h-full w-full items-center justify-center bg-muted/80" />
</AspectRatio>
</div>
</div>
</div>
</div>
</section>
{/* Section 2: مشاوران */}
<section className="bg-muted/30 py-16 md:py-24" id="consultants">
<div className="mx-auto max-w-6xl px-4 md:px-6">
<div className="mx-auto max-w-2xl text-center mb-12">
<h2 className="text-3xl font-bold md:text-4xl">چه کسانی مشاوره می‌دهند؟</h2>
<p className="mt-4 text-muted-foreground">
تیم مشاوره ما متشکل از متخصصان با تجربه در حوزه‌های مختلف فناوری است.
</p>
</div>
<div className="grid gap-8 md:grid-cols-3">
{consultants.map((person) => (
<Card key={person.fallback} className="overflow-hidden">
<CardContent className="pt-6">
<div className="flex flex-col items-center text-center space-y-4">
<Avatar className="h-24 w-24">
<AvatarImage src={person.image} alt={person.name} />
<AvatarFallback className="text-xl">{person.fallback}</AvatarFallback>
</Avatar>
<div>
<h3 className="font-bold text-lg">{person.name}</h3>
<div className="flex flex-wrap justify-center gap-1.5 mt-2">
{person.expertise.map((e) => (
<Badge key={e} variant="secondary" className="text-xs">
{e}
</Badge>
))}
</div>
</div>
<p className="text-sm text-muted-foreground leading-relaxed">
{person.description}
</p>
</div>
</CardContent>
</Card>
))}
</div>
</div>
</section>
{/* Section 3: حوزه‌های مشاوره */}
<section className="bg-background py-16 md:py-24" id="domains">
<div className="mx-auto max-w-6xl px-4 md:px-6">
<div className="mx-auto max-w-2xl text-center mb-12">
<h2 className="text-3xl font-bold md:text-4xl">در چه حوزه‌هایی مشاوره می‌دهیم؟</h2>
<p className="mt-4 text-muted-foreground">
از اینتگریشن و هوشمندسازی تا RAG و بهینه‌سازی عملکرد
</p>
</div>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{domains.map((domain) => {
const Icon = domain.icon
return (
<Card key={domain.title} className="overflow-hidden transition-all hover:shadow-md">
<CardContent className="pt-6">
<div className="flex gap-4">
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
<Icon className="size-6" />
</div>
<div>
<h3 className="font-bold">{domain.title}</h3>
<p className="text-sm text-muted-foreground mt-1 leading-relaxed">
{domain.description}
</p>
</div>
</div>
</CardContent>
</Card>
)
})}
</div>
</div>
</section>
{/* Section 4: فرم درخواست مشاوره */}
<section className="bg-muted/30 py-16 md:py-24" id="consulting-form">
<div className="mx-auto max-w-6xl px-4 md:px-6">
<div className="mx-auto max-w-xl">
<div className="text-center mb-10">
<h2 className="text-3xl font-bold md:text-4xl">درخواست مشاوره</h2>
<p className="mt-4 text-muted-foreground">
فرم زیر را پر کنید؛ در سریع‌ترین زمان ممکن با شما تماس می‌گیریم.
</p>
</div>
<Card className="p-6 md:p-8">
<CardContent className="p-0">
<ConsultingForm />
</CardContent>
</Card>
</div>
</div>
</section>
{/* Section 5: سوالات متداول */}
<section className="bg-background py-16 md:py-24">
<div className="mx-auto max-w-3xl px-4 md:px-6">
<div className="mx-auto max-w-xl text-center mb-12">
<h2 className="text-3xl font-bold md:text-4xl">سوالات متداول</h2>
<p className="mt-4 text-muted-foreground">
پاسخ سوالات رایج درباره مشاوره سازمانی
</p>
</div>
<Accordion type="single" collapsible className="w-full rounded-2xl border bg-muted/30 p-1">
{faqItems.map((item) => (
<AccordionItem
key={item.id}
value={item.id}
className="rounded-xl border-none px-4 data-[state=open]:bg-card data-[state=open]:shadow-sm"
>
<AccordionTrigger className="text-start hover:no-underline py-5">
{item.question}
</AccordionTrigger>
<AccordionContent>
<p className="text-muted-foreground leading-relaxed pb-2">{item.answer}</p>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</section>
</>
)
}
+32
View File
@@ -0,0 +1,32 @@
'use client'
import { useEffect } from 'react'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
console.error(error)
}, [error])
return (
<div className="flex min-h-[60vh] flex-col items-center justify-center gap-6 px-4 text-center">
<h2 className="text-xl font-semibold text-foreground">خطایی رخ داد</h2>
<p className="text-muted-foreground max-w-md text-sm">
لطفاً دوباره تلاش کنید یا به صفحه اصلی برگردید.
</p>
<div className="flex flex-wrap gap-3 justify-center">
<Button onClick={() => reset()}>تلاش مجدد</Button>
<Button asChild variant="outline">
<Link href="/">صفحه اصلی</Link>
</Button>
</div>
</div>
)
}
+23
View File
@@ -0,0 +1,23 @@
import './globals.css'
export const metadata = {
title: '۴۰۴ | صفحه یافت نشد',
description: 'صفحه‌ای که دنبال آن هستید وجود ندارد.',
}
export default function GlobalNotFound() {
return (
<html lang="fa" dir="rtl" suppressHydrationWarning>
<body className="antialiased min-h-svh flex flex-col items-center justify-center gap-6 px-4 bg-background text-foreground">
<h1 className="text-4xl font-bold">۴۰۴</h1>
<p className="text-muted-foreground">این صفحه وجود ندارد.</p>
<a
href="/"
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90"
>
بازگشت به صفحه اصلی
</a>
</body>
</html>
)
}
+21
View File
@@ -0,0 +1,21 @@
import Link from 'next/link'
import { Button } from '@/components/ui/button'
export default function NotFound() {
return (
<div className="flex min-h-[60vh] flex-col items-center justify-center gap-6 px-4 text-center">
<h1 className="text-4xl font-bold text-foreground">۴۰۴</h1>
<p className="text-muted-foreground max-w-md">
صفحه‌ای که دنبال آن هستید یافت نشد.
</p>
<div className="flex flex-wrap gap-3 justify-center">
<Button asChild>
<Link href="/">صفحه اصلی</Link>
</Button>
<Button asChild variant="outline">
<Link href="/consulting">مشاوره سازمانی</Link>
</Button>
</div>
</div>
)
}
+2 -3
View File
@@ -2,7 +2,6 @@ import ContentSection from "@/components/content-1";
import Features from "@/components/features-12";
import { FeaturedPostsGrid } from "@/components/featured-posts-grid";
import { getPosts } from "@/lib/wp-api";
import { HeroHeader } from "@/components/header";
import HeroSection from "@/components/hero-section";
const FEATURED_CATEGORY_ID = 3;
@@ -17,9 +16,9 @@ export default async function Home() {
orderby: "date",
order: "desc",
});
featuredPosts = result.posts;
featuredPosts = result?.posts ?? [];
} catch {
// بدون پست هم صفحه رندر می‌شود
featuredPosts = [];
}
return (