From b39e261ebf7a52707de9c0c6e1c5484fcaf3213e Mon Sep 17 00:00:00 2001 From: navidghanbari Date: Thu, 19 Feb 2026 17:56:02 +0330 Subject: [PATCH] Moshavereh sazmani --- app/api/consulting/route.ts | 82 ++++ app/consulting/page.tsx | 292 +++++++++++++ app/error.tsx | 32 ++ app/global-not-found.tsx | 23 + app/not-found.tsx | 21 + app/page.tsx | 5 +- components/consulting-form.tsx | 200 +++++++++ components/content-1.tsx | 17 +- components/header.tsx | 1 + next.config.ts | 3 + package-lock.json | 379 +++++++++++++++-- yarn.lock | 741 ++++++++++++--------------------- 12 files changed, 1265 insertions(+), 531 deletions(-) create mode 100644 app/api/consulting/route.ts create mode 100644 app/consulting/page.tsx create mode 100644 app/error.tsx create mode 100644 app/global-not-found.tsx create mode 100644 app/not-found.tsx create mode 100644 components/consulting-form.tsx diff --git a/app/api/consulting/route.ts b/app/api/consulting/route.ts new file mode 100644 index 0000000..975507b --- /dev/null +++ b/app/api/consulting/route.ts @@ -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, '>') +} + +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 = [ + '📩 درخواست جدید مشاوره سازمانی', + '', + `نام و نام خانوادگی: ${escapeForTelegram(fullName.trim())}`, + `نام سازمان: ${escapeForTelegram(organization.trim())}`, + `شماره تماس: ${escapeForTelegram(phone.trim())}`, + `حوزه مشاوره: ${escapeForTelegram(area.trim())}`, + ] + if (description?.trim()) { + lines.push('', `توضیحات:`, 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 } + ) + } +} diff --git a/app/consulting/page.tsx b/app/consulting/page.tsx new file mode 100644 index 0000000..dc21146 --- /dev/null +++ b/app/consulting/page.tsx @@ -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 - مشاوره سازمانی */} +
+
+
+
+
+

+ مشاوره سازمانی +

+

+ مشاوره سازمانی به معنای همراهی تخصصی با سازمان شما برای شناسایی چالش‌ها، + انتخاب راهکارهای فنی مناسب و برنامه‌ریزی برای پیاده‌سازی است. ما در حوزه‌های + اینتگریشن، هوشمندسازی، RAG و بهینه‌سازی عملکرد در کنار شما هستیم. +

+

+ شرایط همکاری: پس از ثبت درخواست، تیم ما با شما تماس می‌گیرد؛ جلسه اول برای + شناخت نیازها و تعیین دامنه کار است و در ادامه پیشنهاد و برنامه اجرا ارائه + می‌شود. +

+
+
+ + +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + {/* Section 2: مشاوران */} +
+
+
+

چه کسانی مشاوره می‌دهند؟

+

+ تیم مشاوره ما متشکل از متخصصان با تجربه در حوزه‌های مختلف فناوری است. +

+
+
+ {consultants.map((person) => ( + + +
+ + + {person.fallback} + +
+

{person.name}

+
+ {person.expertise.map((e) => ( + + {e} + + ))} +
+
+

+ {person.description} +

+
+
+
+ ))} +
+
+
+ + {/* Section 3: حوزه‌های مشاوره */} +
+
+
+

در چه حوزه‌هایی مشاوره می‌دهیم؟

+

+ از اینتگریشن و هوشمندسازی تا RAG و بهینه‌سازی عملکرد +

+
+
+ {domains.map((domain) => { + const Icon = domain.icon + return ( + + +
+
+ +
+
+

{domain.title}

+

+ {domain.description} +

+
+
+
+
+ ) + })} +
+
+
+ + {/* Section 4: فرم درخواست مشاوره */} +
+
+
+
+

درخواست مشاوره

+

+ فرم زیر را پر کنید؛ در سریع‌ترین زمان ممکن با شما تماس می‌گیریم. +

+
+ + + + + +
+
+
+ + {/* Section 5: سوالات متداول */} +
+
+
+

سوالات متداول

+

+ پاسخ سوالات رایج درباره مشاوره سازمانی +

+
+ + {faqItems.map((item) => ( + + + {item.question} + + +

{item.answer}

+
+
+ ))} +
+
+
+ + ) +} diff --git a/app/error.tsx b/app/error.tsx new file mode 100644 index 0000000..ade1eb9 --- /dev/null +++ b/app/error.tsx @@ -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 ( +
+

خطایی رخ داد

+

+ لطفاً دوباره تلاش کنید یا به صفحه اصلی برگردید. +

+
+ + +
+
+ ) +} diff --git a/app/global-not-found.tsx b/app/global-not-found.tsx new file mode 100644 index 0000000..b70bc26 --- /dev/null +++ b/app/global-not-found.tsx @@ -0,0 +1,23 @@ +import './globals.css' + +export const metadata = { + title: '۴۰۴ | صفحه یافت نشد', + description: 'صفحه‌ای که دنبال آن هستید وجود ندارد.', +} + +export default function GlobalNotFound() { + return ( + + +

۴۰۴

+

این صفحه وجود ندارد.

+ + بازگشت به صفحه اصلی + + + + ) +} diff --git a/app/not-found.tsx b/app/not-found.tsx new file mode 100644 index 0000000..1a00814 --- /dev/null +++ b/app/not-found.tsx @@ -0,0 +1,21 @@ +import Link from 'next/link' +import { Button } from '@/components/ui/button' + +export default function NotFound() { + return ( +
+

۴۰۴

+

+ صفحه‌ای که دنبال آن هستید یافت نشد. +

+
+ + +
+
+ ) +} diff --git a/app/page.tsx b/app/page.tsx index 2117cb7..4b65625 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -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 ( diff --git a/components/consulting-form.tsx b/components/consulting-form.tsx new file mode 100644 index 0000000..8a12836 --- /dev/null +++ b/components/consulting-form.tsx @@ -0,0 +1,200 @@ +'use client' + +import { useState } from 'react' +import { useForm } from 'react-hook-form' +import { zodResolver } from '@hookform/resolvers/zod' +import { z } from 'zod' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Textarea } from '@/components/ui/textarea' +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { Alert, AlertDescription } from '@/components/ui/alert' +import { CheckCircle2, Loader2 } from 'lucide-react' + +const consultingAreas = [ + 'اینتگریشن', + 'هوشمندسازی', + 'RAG', + 'Performance', + 'امنیت', + 'معماری نرم‌افزار', + 'داده و تحلیل', + 'سایر', +] as const + +const formSchema = z.object({ + fullName: z.string().min(2, 'نام و نام خانوادگی الزامی است'), + organization: z.string().min(1, 'نام سازمان الزامی است'), + phone: z.string().min(10, 'شماره تماس معتبر وارد کنید'), + area: z.string().min(1, 'حوزه مشاوره را انتخاب کنید'), + description: z.string().optional(), +}) + +type FormValues = z.infer + +export function ConsultingForm() { + const [submitted, setSubmitted] = useState(false) + const [isSubmitting, setIsSubmitting] = useState(false) + const [submitError, setSubmitError] = useState(null) + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + fullName: '', + organization: '', + phone: '', + area: '', + description: '', + }, + }) + + async function onSubmit(data: FormValues) { + setSubmitError(null) + setIsSubmitting(true) + try { + const res = await fetch('/api/consulting', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }) + const json = await res.json().catch(() => ({})) + if (!res.ok) { + setSubmitError(json.error || 'ارسال درخواست ناموفق بود. لطفاً دوباره تلاش کنید.') + return + } + setSubmitted(true) + form.reset() + } catch { + setSubmitError('خطا در ارتباط با سرور. لطفاً دوباره تلاش کنید.') + } finally { + setIsSubmitting(false) + } + } + + if (submitted) { + return ( + + + + در سریع‌ترین زمان ممکن با شما تماس می‌گیریم. + + + ) + } + + return ( +
+ + {submitError && ( + + {submitError} + + )} + ( + + نام و نام خانوادگی + + + + + + )} + /> + ( + + نام سازمان + + + + + + )} + /> + ( + + شماره تماس + + + + + + )} + /> + ( + + در چه حوزه‌ای مشاوره می‌خواهید؟ + + + + )} + /> + ( + + توضیحات (اختیاری) + +