Merge branch 'main' of https://git.feep.ir/ahmadreza6137/next-ArAB
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/next-ArAB.iml" filepath="$PROJECT_DIR$/.idea/next-ArAB.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+19
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,3 +1,9 @@
|
||||
export const metadata = {
|
||||
title: "درباره ما",
|
||||
description:
|
||||
"فیپ یک گروه متخصص در حوزه اینتگریشن و روشهای نوین یکپارچهسازی. ماموریت، چشمانداز و ارزشهای ما.",
|
||||
};
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
/** API بله سازگار با API تلگرام — مستندات: https://dev.bale.ai */
|
||||
const BALE_API = 'https://tapi.bale.ai'
|
||||
|
||||
export interface ConsultingRequestBody {
|
||||
fullName: string
|
||||
organization: string
|
||||
phone: string
|
||||
area: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
function escapeHtml(text: string): string {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const token = process.env.BALE_BOT_TOKEN
|
||||
const chatId = process.env.BALE_CHAT_ID
|
||||
|
||||
if (!token || !chatId) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error:
|
||||
'بله پیکربندی نشده است. BALE_BOT_TOKEN و BALE_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 = [
|
||||
'📩 درخواست جدید مشاوره سازمانی',
|
||||
'────────────────',
|
||||
`👤 نام و نام خانوادگی: ${escapeHtml(fullName.trim())}`,
|
||||
`🏢 نام سازمان: ${escapeHtml(organization.trim())}`,
|
||||
`📱 شماره تماس: ${escapeHtml(phone.trim())}`,
|
||||
`📋 حوزه مشاوره: ${escapeHtml(area.trim())}`,
|
||||
]
|
||||
if (description?.trim()) {
|
||||
lines.push('', `💬 توضیحات:\n${escapeHtml(description.trim())}`)
|
||||
}
|
||||
|
||||
const text = lines.join('\n')
|
||||
|
||||
try {
|
||||
const res = await fetch(`${BALE_API}/bot${token}/sendMessage`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
chat_id: chatId,
|
||||
text,
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await res.json().catch(() => ({}))
|
||||
if (!res.ok) {
|
||||
return NextResponse.json(
|
||||
{ error: data.description || 'ارسال به بله ناموفق بود' },
|
||||
{ status: 502 }
|
||||
)
|
||||
}
|
||||
return NextResponse.json({ ok: true })
|
||||
} catch {
|
||||
return NextResponse.json({ error: 'خطا در ارتباط با بله' }, { status: 502 })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
/**
|
||||
* پاک کردن کش مقالات وردپرس.
|
||||
* وقتی در وردپرس مقالهای منتشر یا ویرایش شد، این آدرس را با secret فراخوانی کنید
|
||||
* تا کش دانشنامه و مقالهها بدون ریستارت سرور بهروز شود.
|
||||
*
|
||||
* استفاده در وردپرس:
|
||||
* - با پلاگین Webhook یا کد تم: بعد از save_post درخواست به این آدرس بفرست.
|
||||
* - مثال: GET یا POST /api/revalidate?secret=YOUR_REVALIDATE_SECRET
|
||||
* - یا هدر: x-revalidate-secret: YOUR_REVALIDATE_SECRET
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
return handleRevalidate(request);
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
return handleRevalidate(request);
|
||||
}
|
||||
|
||||
async function handleRevalidate(request: NextRequest) {
|
||||
const secret = process.env.REVALIDATE_SECRET;
|
||||
if (!secret) {
|
||||
return NextResponse.json(
|
||||
{ error: "REVALIDATE_SECRET تنظیم نشده است." },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const provided =
|
||||
request.nextUrl.searchParams.get("secret") ??
|
||||
request.headers.get("x-revalidate-secret");
|
||||
if (provided !== secret) {
|
||||
return NextResponse.json({ error: "غیرمجاز" }, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
revalidateTag("blog-posts");
|
||||
return NextResponse.json({ revalidated: true, now: Date.now() });
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: "خطا در پاک کردن کش" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,33 @@ interface BlogPostPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
function stripHtml(html: string): string {
|
||||
return html.replace(/<[^>]*>/g, "").trim();
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: BlogPostPageProps): Promise<Metadata> {
|
||||
const { slug } = await params;
|
||||
const post = await getPostBySlug(slug);
|
||||
if (!post) return { title: "پست یافت نشد" };
|
||||
const title = post.title?.rendered ?? "پست";
|
||||
const excerpt = post.excerpt?.rendered?.replace(/<[^>]*>/g, "").trim().slice(0, 160) ?? "";
|
||||
const titleRaw = post.title?.rendered ?? "پست";
|
||||
const title = stripHtml(titleRaw);
|
||||
const excerpt = stripHtml(post.excerpt?.rendered ?? "").slice(0, 160);
|
||||
const imageUrl = getFeaturedImageUrl(post, "medium_large");
|
||||
return {
|
||||
title,
|
||||
title: titleRaw,
|
||||
description: excerpt,
|
||||
openGraph: {
|
||||
title,
|
||||
description: excerpt,
|
||||
...(imageUrl && { images: [{ url: imageUrl, alt: title }] }),
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title,
|
||||
description: excerpt,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ const PER_PAGE = 9;
|
||||
export const metadata: Metadata = {
|
||||
title: "دانشنامه",
|
||||
description: "مقالات و مطالب فیپ در زمینه یکپارچهسازی، اتوماسیون و بهرهوری سازمانی.",
|
||||
openGraph: {
|
||||
title: "دانشنامه",
|
||||
description: "مقالات و مطالب فیپ در زمینه یکپارچهسازی، اتوماسیون و بهرهوری سازمانی.",
|
||||
},
|
||||
};
|
||||
|
||||
interface BlogPageProps {
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
import { AspectRatio } from '@/components/ui/aspect-ratio'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
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,
|
||||
Shield,
|
||||
Layout,
|
||||
BarChart3,
|
||||
HelpCircle,
|
||||
Quote,
|
||||
} 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: 'امنیت',
|
||||
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="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 3: چه کسانی مشاوره میدهند؟ — سبک Testimonial */}
|
||||
<section className="bg-background 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 border-border/60 shadow-sm">
|
||||
<CardContent className="p-6 md:p-8">
|
||||
<Quote className="size-10 text-primary/30 mb-4" aria-hidden />
|
||||
<blockquote className="text-muted-foreground leading-relaxed mb-6">
|
||||
{person.description}
|
||||
</blockquote>
|
||||
<div className="flex items-center gap-4">
|
||||
<Avatar className="h-14 w-14 shrink-0 border-2 border-background shadow">
|
||||
<AvatarImage src={person.image} alt={person.name} />
|
||||
<AvatarFallback className="text-lg bg-primary/10 text-primary">
|
||||
{person.fallback}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<h3 className="font-bold text-foreground">{person.name}</h3>
|
||||
<div className="flex flex-wrap gap-1.5 mt-1">
|
||||
{person.expertise.map((e) => (
|
||||
<span key={e} className="text-xs text-muted-foreground">
|
||||
{e}
|
||||
{e !== person.expertise[person.expertise.length - 1] ? ' · ' : ''}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 4: سوالات متداول (جابجا شده با فرم) */}
|
||||
<section className="bg-muted/30 py-16 md:py-24" id="faq">
|
||||
<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-background/80 p-1 shadow-sm">
|
||||
{faqItems.map((item) => (
|
||||
<AccordionItem
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
className="rounded-xl border-none px-4 data-[state=open]:bg-muted/50 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>
|
||||
|
||||
{/* Section 5: فرم درخواست مشاوره (جابجا شده با FAQ) */}
|
||||
<section className="bg-background 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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import './globals.css'
|
||||
import Link from 'next/link'
|
||||
|
||||
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 px-4 py-20 bg-background text-foreground">
|
||||
<div className="mx-auto max-w-lg w-full text-center">
|
||||
<div className="relative inline-block mb-6">
|
||||
<span
|
||||
className="text-[8rem] md:text-[10rem] font-black leading-none tracking-tighter text-transparent bg-clip-text bg-gradient-to-b from-primary/90 to-primary/50 select-none"
|
||||
aria-hidden
|
||||
>
|
||||
۴۰۴
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-2xl font-bold text-foreground mb-3">
|
||||
صفحه پیدا نشد
|
||||
</h1>
|
||||
<p className="text-muted-foreground mb-10 max-w-sm mx-auto leading-relaxed">
|
||||
به نظر میرسد این آدرس وجود ندارد یا منتقل شده است.
|
||||
</p>
|
||||
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center gap-2 h-11 px-6 rounded-md bg-primary text-primary-foreground font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
||||
صفحه اصلی
|
||||
</Link>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
+9
-3
@@ -5,10 +5,16 @@ import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { TopProgressBar } from "@/components/top-progress-bar";
|
||||
|
||||
|
||||
const SITE_NAME = "فیپ";
|
||||
const DEFAULT_DESCRIPTION =
|
||||
"فیپ یک سامانه برای ایجاد و طراحی راهکارهای مناسب برای کسب و کار شما است.";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "فیپ",
|
||||
description:
|
||||
"فیپ یک سامانه برای ایجاد و طراحی راهکارهای مناسب برای کسب و کار شما است.",
|
||||
title: {
|
||||
default: `${SITE_NAME} | راهکارهای یکپارچه و هوشمند برای کسبوکار`,
|
||||
template: `%s | ${SITE_NAME}`,
|
||||
},
|
||||
description: DEFAULT_DESCRIPTION,
|
||||
icons: {
|
||||
icon: "/assets/feep-Logo.svg",
|
||||
},
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { Metadata } from "next";
|
||||
import { LoginForm } from "@/components/login-form";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "ورود",
|
||||
description: "ورود به حساب فیپ",
|
||||
};
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<div className="container mx-auto flex min-h-screen items-center justify-center px-4 py-16">
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Home } from 'lucide-react'
|
||||
|
||||
export const metadata = {
|
||||
title: '۴۰۴',
|
||||
description: 'صفحهای که دنبال آن هستید یافت نشد.',
|
||||
}
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<section className="min-h-[70vh] flex items-center justify-center px-4 py-20">
|
||||
<div className="mx-auto max-w-lg w-full text-center">
|
||||
<div className="relative inline-block mb-6">
|
||||
<span
|
||||
className="text-[8rem] md:text-[10rem] font-black leading-none tracking-tighter text-transparent bg-clip-text bg-gradient-to-b from-primary/90 to-primary/50 select-none"
|
||||
aria-hidden
|
||||
>
|
||||
۴۰۴
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-2xl font-bold text-foreground mb-3">
|
||||
صفحه پیدا نشد
|
||||
</h1>
|
||||
<p className="text-muted-foreground mb-10 max-w-sm mx-auto leading-relaxed">
|
||||
به نظر میرسد این آدرس وجود ندارد یا منتقل شده است.
|
||||
</p>
|
||||
|
||||
<Button asChild size="lg" className="gap-2">
|
||||
<Link href="/">
|
||||
<Home className="size-5" />
|
||||
صفحه اصلی
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
+8
-3
@@ -1,10 +1,15 @@
|
||||
import type { Metadata } from "next";
|
||||
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";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
description:
|
||||
"فیپ؛ راهکارهای یکپارچه و هوشمند برای اتصال سیستمها، اتوماسیون فرآیندها و بهرهوری کسبوکار.",
|
||||
};
|
||||
|
||||
const FEATURED_CATEGORY_ID = 3;
|
||||
const FEATURED_POSTS_COUNT = 4;
|
||||
|
||||
@@ -17,9 +22,9 @@ export default async function Home() {
|
||||
orderby: "date",
|
||||
order: "desc",
|
||||
});
|
||||
featuredPosts = result.posts;
|
||||
featuredPosts = result?.posts ?? [];
|
||||
} catch {
|
||||
// بدون پست هم صفحه رندر میشود
|
||||
featuredPosts = [];
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import type { Metadata } from "next";
|
||||
import Pricing from "@/components/pricing";
|
||||
import PricingComparator from "@/components/pricing-comparator";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "قیمتگذاری",
|
||||
description: "تعرفه و پلنهای خدمات فیپ. انتخاب مناسب برای کسبوکار شما.",
|
||||
};
|
||||
|
||||
export default function PricingPage() {
|
||||
return (
|
||||
<>
|
||||
|
||||
+85
-49
@@ -1,74 +1,87 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Link as LinkIcon, BarChart3, Share2, Zap, TrendingUp, Workflow } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "راه حلها",
|
||||
description:
|
||||
"راهکارهای فیپ: یکپارچهسازی سیستمها، پنلهای مدیریتی، اتوماسیون فرآیندها و تحلیل داده.",
|
||||
};
|
||||
|
||||
const solutions = [
|
||||
{
|
||||
icon: LinkIcon,
|
||||
title: "یکپارچهسازی سیستمها",
|
||||
description: "اتصال و هماهنگسازی سیستمها و سرویسهای مختلف برای ایجاد جریان یکپارچه داده و فرآیند",
|
||||
description:
|
||||
"در بسیاری از شرکتها، نرمافزارها و سرویسهای مختلف مثل CRM، مدیریت مالی یا پشتیبانی با هم ارتباط ندارند. این موضوع باعث اتلاف وقت، اشتباه در دادهها و تجربه کاربری ضعیف میشود. راهکار یکپارچهسازی به شما اجازه میدهد تا:",
|
||||
features: [
|
||||
"اتصال به سرویسها و APIهای مختلف",
|
||||
"همگامسازی خودکار دادهها بین سیستمها",
|
||||
"ایجاد workflowهای یکپارچه",
|
||||
"پشتیبانی از پروتکلهای مختلف ارتباطی"
|
||||
]
|
||||
"سیستمهای مختلف را به هم وصل کنید و دادهها همزمان در همه جا بهروز شوند",
|
||||
"دادهها بدون دخالت انسانی بین ابزارها منتقل شود",
|
||||
"فرایندهای تکراری حذف شوند",
|
||||
],
|
||||
result: "این یعنی حذف خطاهای انسانی، صرفهجویی در وقت و تمرکز روی تصمیمهای درست.",
|
||||
},
|
||||
{
|
||||
icon: BarChart3,
|
||||
title: "پنلهای مدیریتی قدرتمند",
|
||||
description: "ارائه پنلهای کاربری پیشرفته برای نمایش آمار، تحلیل دادهها و مدیریت اطلاعات با رابط کاربری حرفهای",
|
||||
title: "داشبوردها و پنلهای مدیریتی قدرتمند",
|
||||
description:
|
||||
"داشتن اطلاعات بهموقع، کلید تصمیمگیری دقیق است. راهکارهای مدیریتی پیشرفته امکان میدهند تا:",
|
||||
features: [
|
||||
"داشبوردهای تعاملی و قابل تنظیم",
|
||||
"نمایش آمار و گزارشهای زنده",
|
||||
"ویرایش و مدیریت اطلاعات از طریق UI",
|
||||
"نمودارها و تجسمهای داده پیشرفته"
|
||||
]
|
||||
"همه اطلاعات مهم کسبوکار را در یک نمایشگر واحد ببینید",
|
||||
"گزارشهای لحظهای و قابل تنظیم داشته باشید",
|
||||
"روندها، شاخصهای کلیدی و فرصتها را سریع تشخیص دهید",
|
||||
],
|
||||
result: "این نوع داشبوردها باعث میشود بهجای حدس و گمان، تصمیمهای مبتنی بر داده بگیرید.",
|
||||
},
|
||||
{
|
||||
icon: Share2,
|
||||
title: "تعامل با شبکههای اجتماعی",
|
||||
description: "ایجاد ارتباطات قدرتمند و خودکار با پلتفرمهای مختلف شبکههای اجتماعی برای مدیریت و تعامل بهتر",
|
||||
title: "تعامل هوشمند با شبکههای اجتماعی",
|
||||
description:
|
||||
"امروزه شبکههای اجتماعی نقش مهمی در ارتباط با مشتریان دارند. راهکارهای یکپارچهسازی تعامل اجتماعی به شما امکان میدهند تا:",
|
||||
features: [
|
||||
"اتصال به پلتفرمهای مختلف اجتماعی",
|
||||
"مدیریت و ارسال محتوا به صورت خودکار",
|
||||
"نظارت و تحلیل تعاملات",
|
||||
"همگامسازی اطلاعات بین پلتفرمها"
|
||||
]
|
||||
"محتوا را بهصورت خودکار منتشر کنید",
|
||||
"تعاملات کاربران در شبکههای مختلف را تحلیل کنید",
|
||||
"تحلیل دادههای اجتماعی را برای بهبود تجربه مشتری در کسبوکارتان بهکار ببرید",
|
||||
],
|
||||
result: "این یعنی مدیریت بهتر برند، افزایش تعامل و شناخت عمیقتر مشتریان.",
|
||||
},
|
||||
{
|
||||
icon: Zap,
|
||||
title: "اتوماسیون فرآیندها",
|
||||
description: "ایجاد کارهای خودکار برای اتوماتیکسازی فرآیندهای کسبوکار و کاهش کارهای دستی",
|
||||
description:
|
||||
"بخش زیادی از کارهای روزمره در کسبوکار قابل خودکارسازی هستند. با اتوماسیون فرایندها میتوانید:",
|
||||
features: [
|
||||
"تعریف و اجرای workflowهای خودکار",
|
||||
"اتوماسیون بر اساس رویداد و زمان",
|
||||
"زمانبندی و اجرای کارهای تکراری",
|
||||
"اعلانها و هشدارهای خودکار"
|
||||
]
|
||||
"فعالیتهای تکراری را بدون دخالت انسانی اجرا کنید",
|
||||
"اعلانهای هوشمند تنظیم کنید تا تیم شما فقط روی کارهای مهم تمرکز کند",
|
||||
"چرخههای کاری را بهینه کنید تا خطا کمتر شود و سرعت اجرا بیشتر",
|
||||
],
|
||||
result: "این نوع اتوماسیون کمک میکند تا منابع انسانی شما روی فعالیتهای ارزشآفرین تمرکز کنند.",
|
||||
},
|
||||
{
|
||||
icon: TrendingUp,
|
||||
title: "تحلیل و پردازش داده",
|
||||
description: "انجام تحلیلهای پیشرفته روی دادهها و پردازش اطلاعات برای استخراج منابع ارزشمند",
|
||||
title: "تحلیل و پردازش دادهها",
|
||||
description:
|
||||
"اطلاعات خام زمانی ارزشمند میشود که بتوانید با آن تصمیمهای هوشمند بگیرید. این راهکار شامل:",
|
||||
features: [
|
||||
"تحلیل دادهها از منابع مختلف",
|
||||
"پردازش و تبدیل دادهها",
|
||||
"گزارشگیری و تجسم نتایج",
|
||||
"شناسایی الگوها و روندها"
|
||||
]
|
||||
"تحلیلهای پیشرفته روی دادههای جمعآوریشده از منابع مختلف",
|
||||
"گزارشگیری و شناسایی الگوها و روندها در دادهها",
|
||||
"تبدیل داده به بینش عملیاتی",
|
||||
],
|
||||
result: "که به شما کمک میکند درک بهتری از عملکرد، مشتریان و فرصتهای رشد داشته باشید.",
|
||||
},
|
||||
{
|
||||
icon: Workflow,
|
||||
title: "مدیریت جریان کار",
|
||||
description: "طراحی و مدیریت جریانهای کاری پیچیده برای اتصال و هماهنگسازی فرآیندهای مختلف",
|
||||
title: "مدیریت جریانهای کاری پیچیده",
|
||||
description:
|
||||
"وقتی کسبوکار رشد میکند، فرایندها پیچیدهتر میشوند. مدیریت جریان کار به شما این امکان را میدهد تا:",
|
||||
features: [
|
||||
"طراحی workflowهای سفارشی",
|
||||
"مدیریت و نظارت بر اجرای فرآیندها",
|
||||
"خطایابی و بهینهسازی جریانها",
|
||||
"لاگ و گزارشگیری از اجراها"
|
||||
]
|
||||
}
|
||||
"فرآیندهای چندمرحلهای را طراحی و نظارت کنید",
|
||||
"ایرادات فرایندها را سریع پیدا و برطرف کنید",
|
||||
"خروجی کارها را بهطور کامل رهگیری کنید",
|
||||
],
|
||||
result: "این موضوع باعث میشود فرایندها استاندارد، قابل اندازهگیری و همیشه بهتر شوند.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function SolutionsPage() {
|
||||
@@ -81,36 +94,39 @@ export default function SolutionsPage() {
|
||||
<h1 className="text-4xl font-bold md:text-5xl lg:text-6xl leading-tight tracking-normal">
|
||||
راهحلهای ما
|
||||
</h1>
|
||||
<p className="text-xl leading-relaxed tracking-normal text-muted-foreground max-w-2xl mx-auto">
|
||||
راهحلهای یکپارچهسازی پیشرفته برای اتصال سیستمها، اتوماسیون فرآیندها، تعامل با شبکههای اجتماعی و تحلیل دادهها که کسبوکار شما را به سطح جدیدی از کارایی میرساند.
|
||||
<p className="text-xl leading-relaxed tracking-normal text-muted-foreground max-w-3xl mx-auto">
|
||||
در دنیای امروز، کسبوکارهای موفق دیگر نمیتوانند سیستمها، ابزارها و دادههایشان را جدا از هم مدیریت کنند. حجم اطلاعات، تعداد ابزارهای مختلف و نیاز به واکنش سریع باعث شده تا یکپارچهسازی واقعی سیستمها دیگر تنها یک انتخاب نباشد — بلکه یک ضرورت باشد.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed tracking-normal text-muted-foreground max-w-3xl mx-auto">
|
||||
راهکارهایی که اینجا معرفی میشود، فراتر از تکنولوژیهای معمول است. هدف اصلی این نیست که فقط چند سرویس را به هم وصل کنیم، بلکه این است که فرایندهای کسبوکار شما را هوشمند، کارا و قابل کنترلتر کنیم.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Solutions Grid */}
|
||||
{/* Solutions */}
|
||||
<section className="bg-muted/30 py-20 md:py-28">
|
||||
<div className="mx-auto max-w-6xl px-6">
|
||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-2">
|
||||
<div className="space-y-16">
|
||||
{solutions.map((solution, index) => {
|
||||
const Icon = solution.icon;
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="group rounded-2xl border bg-card p-8 transition-all duration-300 hover:shadow-lg hover:-translate-y-1"
|
||||
className="group rounded-2xl border bg-card p-8 md:p-10 transition-all duration-300 hover:shadow-lg"
|
||||
>
|
||||
<div className="mb-6 flex items-center gap-4">
|
||||
<div className="flex size-14 items-center justify-center rounded-xl bg-primary/10 text-primary shrink-0">
|
||||
<Icon className="size-7" />
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold leading-tight tracking-normal">
|
||||
{solution.title}
|
||||
{index + 1}. {solution.title}
|
||||
</h2>
|
||||
</div>
|
||||
<p className="mb-6 leading-relaxed tracking-normal text-muted-foreground text-lg">
|
||||
{solution.description}
|
||||
</p>
|
||||
<ul className="space-y-3">
|
||||
<ul className="space-y-3 mb-6">
|
||||
{solution.features.map((feature, featureIndex) => (
|
||||
<li
|
||||
key={featureIndex}
|
||||
@@ -121,6 +137,11 @@ export default function SolutionsPage() {
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{solution.result && (
|
||||
<p className="text-base leading-relaxed tracking-normal text-foreground/90 font-medium border-r-4 border-primary/50 pr-4">
|
||||
{solution.result}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -128,8 +149,23 @@ export default function SolutionsPage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* نتیجهگیری */}
|
||||
<section className="bg-background py-16 md:py-24">
|
||||
<div className="mx-auto max-w-4xl px-6">
|
||||
<div className="rounded-2xl border bg-muted/30 p-8 md:p-10">
|
||||
<h2 className="text-2xl font-bold mb-6">نتیجهگیری</h2>
|
||||
<p className="text-lg leading-relaxed text-muted-foreground mb-4">
|
||||
این راهکارها کمک میکنند تا کسبوکار شما از حالت «جزیرهای» بیرون بیاید و به یک ساختار هوشمند، بههمپیوسته و قابل رشد تبدیل شود.
|
||||
</p>
|
||||
<p className="text-lg leading-relaxed text-muted-foreground">
|
||||
دیگر لازم نیست زمان زیادی صرف انتقال داده، گزارشگیری دستی یا تکرار فعالیتها بکنید؛ بلکه میتوانید بهطور هوشمندانهتر روی اهداف استراتژیک خود تمرکز کنید و رشد سریعتر را تجربه کنید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="bg-background py-20 md:py-28">
|
||||
<section className="bg-muted/30 py-20 md:py-28">
|
||||
<div className="mx-auto max-w-4xl px-6">
|
||||
<div className="text-center space-y-8 p-12 rounded-2xl border bg-gradient-to-br from-primary/5 to-primary/10">
|
||||
<h2 className="text-3xl font-bold md:text-4xl leading-tight tracking-normal">
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
'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(1, 'شماره تماس الزامی است')
|
||||
.refine(
|
||||
(val) => {
|
||||
const normalized = val
|
||||
.replace(/[۰-۹]/g, (c) => '۰۱۲۳۴۵۶۷۸۹'.indexOf(c).toString())
|
||||
.replace(/\D/g, '')
|
||||
return normalized.length === 11 && normalized.startsWith('09')
|
||||
},
|
||||
'لطفاً شماره موبایل معتبر وارد کنید'
|
||||
),
|
||||
area: z.string().min(1, 'حوزه مشاوره را انتخاب کنید'),
|
||||
description: z.string().max(1000, 'حداکثر ۱۰۰۰ کاراکتر مجاز است').optional(),
|
||||
})
|
||||
|
||||
type FormValues = z.infer<typeof formSchema>
|
||||
|
||||
export function ConsultingForm() {
|
||||
const [submitted, setSubmitted] = useState(false)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [submitError, setSubmitError] = useState<string | null>(null)
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
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 (
|
||||
<Alert className="border-primary/50 bg-primary/5 text-center">
|
||||
<CheckCircle2 className="h-5 w-5 text-primary" />
|
||||
<AlertDescription className="text-base font-medium">
|
||||
در سریعترین زمان ممکن با شما تماس میگیریم.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||
{submitError && (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{submitError}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="fullName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>نام و نام خانوادگی</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="نام و نام خانوادگی" {...field} className="h-11" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="organization"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>نام سازمان</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="نام سازمان یا شرکت" {...field} className="h-11" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phone"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>شماره تماس</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="tel" placeholder="۰۹۱۲۳۴۵۶۷۸۹" {...field} className="h-11" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="area"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>در چه حوزهای مشاوره میخواهید؟</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger className="h-11 w-full">
|
||||
<SelectValue placeholder="انتخاب حوزه" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{consultingAreas.map((area) => (
|
||||
<SelectItem key={area} value={area}>
|
||||
{area}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>توضیحات (اختیاری)</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder="در صورت نیاز توضیح بیشتری بنویسید..."
|
||||
className="min-h-24"
|
||||
maxLength={1000}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" size="lg" className="w-full" disabled={isSubmitting}>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<Loader2 className="size-5 animate-spin" aria-hidden />
|
||||
در حال ارسال...
|
||||
</>
|
||||
) : (
|
||||
'ثبت درخواست'
|
||||
)}
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
@@ -10,13 +10,16 @@ export default function ContentSection() {
|
||||
<div className="grid gap-6 sm:grid-cols-2 md:gap-12 lg:gap-24">
|
||||
<div className="relative mb-6 sm:mb-0">
|
||||
<div className="bg-linear-to-b aspect-76/59 relative rounded-2xl from-zinc-300 to-transparent p-px dark:from-zinc-700">
|
||||
<Image
|
||||
src="/assets/Echosystem.png"
|
||||
className="rounded-[15px] object-cover"
|
||||
alt="اکوسیستم یکپارچه فیپ"
|
||||
width={1207}
|
||||
height={929}
|
||||
/>
|
||||
<div className="relative aspect-[1207/929] w-full overflow-hidden rounded-[15px] bg-muted flex items-center justify-center">
|
||||
<Image
|
||||
src="/assets/Echosystem.png"
|
||||
className="rounded-[15px] object-cover"
|
||||
alt="اکوسیستم یکپارچه فیپ"
|
||||
width={1207}
|
||||
height={929}
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const menuItems = [
|
||||
{ name: 'صفحه اصلی', href: '/' },
|
||||
{ name: 'دانشنامه', href: '/blog' },
|
||||
{ name: 'راه حلها', href: '/solutions' },
|
||||
{ name: 'مشاوره سازمانی', href: '/consulting' },
|
||||
// { name: 'قیمتگذاری', href: '/pricing' },
|
||||
{ name: 'درباره ما', href: '/about' },
|
||||
]
|
||||
|
||||
+8
-1
@@ -1,6 +1,10 @@
|
||||
const WP_API_BASE = "https://wpa.feep.ir/wp-json/wp/v2";
|
||||
const FETCH_TIMEOUT_MS = 15_000;
|
||||
|
||||
/** کش مقالات وردپرس: یک ساعت. با revalidateTag('blog-posts') از API میتوان کش را پاک کرد. */
|
||||
const CACHE_REVALIDATE_SECONDS = 3600;
|
||||
const CACHE_TAG_BLOG = "blog-posts";
|
||||
|
||||
export interface WpMediaSize {
|
||||
source_url: string;
|
||||
width?: number;
|
||||
@@ -86,7 +90,10 @@ async function fetchWithTimeout(
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
signal: controller.signal,
|
||||
next: { revalidate: 0 },
|
||||
next: {
|
||||
revalidate: CACHE_REVALIDATE_SECONDS,
|
||||
tags: [CACHE_TAG_BLOG],
|
||||
},
|
||||
});
|
||||
clearTimeout(timeout);
|
||||
return res;
|
||||
|
||||
@@ -2,6 +2,9 @@ import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: 'standalone',
|
||||
experimental: {
|
||||
globalNotFound: true,
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
|
||||
Generated
+339
-40
@@ -36,15 +36,17 @@
|
||||
"@radix-ui/react-toggle": "^1.1.10",
|
||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"cheerio": "^1.0.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-jalali": "^4.1.0-0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"input-otp": "^1.4.2",
|
||||
"lucide-react": "^0.555.0",
|
||||
"motion": "^12.23.25",
|
||||
"next": "16.0.6",
|
||||
"next": "16.0.10",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.0",
|
||||
"react-day-picker": "^9.11.3",
|
||||
@@ -1167,9 +1169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.6.tgz",
|
||||
"integrity": "sha512-PFTK/G/vM3UJwK5XDYMFOqt8QW42mmhSgdKDapOlCqBUAOfJN2dyOnASR/xUR/JRrro0pLohh/zOJ77xUQWQAg==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz",
|
||||
"integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
@@ -1183,9 +1185,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.6.tgz",
|
||||
"integrity": "sha512-AGzKiPlDiui+9JcPRHLI4V9WFTTcKukhJTfK9qu3e0tz+Y/88B7vo5yZoO7UaikplJEHORzG3QaBFQfkjhnL0Q==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.10.tgz",
|
||||
"integrity": "sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1199,9 +1201,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.6.tgz",
|
||||
"integrity": "sha512-LlLLNrK9WCIUkq2GciWDcquXYIf7vLxX8XE49gz7EncssZGL1vlHwgmURiJsUZAvk0HM1a8qb1ABDezsjAE/jw==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz",
|
||||
"integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1215,9 +1217,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.6.tgz",
|
||||
"integrity": "sha512-r04NzmLSGGfG8EPXKVK72N5zDNnq9pa9el78LhdtqIC3zqKh74QfKHnk24DoK4PEs6eY7sIK/CnNpt30oc59kg==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz",
|
||||
"integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1231,9 +1233,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.6.tgz",
|
||||
"integrity": "sha512-hfB/QV0hA7lbD1OJxp52wVDlpffUMfyxUB5ysZbb/pBC5iuhyLcEKSVQo56PFUUmUQzbMsAtUu6k2Gh9bBtWXA==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz",
|
||||
"integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1247,9 +1249,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.6.tgz",
|
||||
"integrity": "sha512-PZJushBgfvKhJBy01yXMdgL+l5XKr7uSn5jhOQXQXiH3iPT2M9iG64yHpPNGIKitKrHJInwmhPVGogZBAJOCPw==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz",
|
||||
"integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1263,9 +1265,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.6.tgz",
|
||||
"integrity": "sha512-LqY76IojrH9yS5fyATjLzlOIOgwyzBuNRqXwVxcGfZ58DWNQSyfnLGlfF6shAEqjwlDNLh4Z+P0rnOI87Y9jEw==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz",
|
||||
"integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1279,9 +1281,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.6.tgz",
|
||||
"integrity": "sha512-eIfSNNqAkj0tqKRf0u7BVjqylJCuabSrxnpSENY3YKApqwDMeAqYPmnOwmVe6DDl3Lvkbe7cJAyP6i9hQ5PmmQ==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz",
|
||||
"integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1295,9 +1297,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.6.tgz",
|
||||
"integrity": "sha512-QGs18P4OKdK9y2F3Th42+KGnwsc2iaThOe6jxQgP62kslUU4W+g6AzI6bdIn/pslhSfxjAMU5SjakfT5Fyo/xA==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz",
|
||||
"integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -4239,6 +4241,12 @@
|
||||
"baseline-browser-mapping": "dist/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
@@ -4394,6 +4402,48 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
|
||||
"integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cheerio-select": "^2.1.0",
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.2.2",
|
||||
"encoding-sniffer": "^0.2.1",
|
||||
"htmlparser2": "^10.1.0",
|
||||
"parse5": "^7.3.0",
|
||||
"parse5-htmlparser2-tree-adapter": "^7.1.0",
|
||||
"parse5-parser-stream": "^7.1.2",
|
||||
"undici": "^7.19.0",
|
||||
"whatwg-mimetype": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.18.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio-select": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
|
||||
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-select": "^5.1.0",
|
||||
"css-what": "^6.1.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
||||
@@ -4486,6 +4536,34 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
||||
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.1.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"domutils": "^3.0.1",
|
||||
"nth-check": "^2.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css-what": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
||||
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
@@ -4796,6 +4874,61 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domelementtype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -4853,6 +4986,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encoding-sniffer": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
|
||||
"integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.3",
|
||||
"whatwg-encoding": "^3.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
@@ -4867,6 +5013,18 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.24.0",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
|
||||
@@ -5995,6 +6153,49 @@
|
||||
"hermes-estree": "0.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
||||
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.2.2",
|
||||
"entities": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2/node_modules/entities": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
||||
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -7127,12 +7328,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.0.6",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.0.6.tgz",
|
||||
"integrity": "sha512-2zOZ/4FdaAp5hfCU/RnzARlZzBsjaTZ/XjNQmuyYLluAPM7kcrbIkdeO2SL0Ysd1vnrSgU+GwugfeWX1cUCgCg==",
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.0.10.tgz",
|
||||
"integrity": "sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.0.6",
|
||||
"@next/env": "16.0.10",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"postcss": "8.4.31",
|
||||
@@ -7145,14 +7346,14 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.0.6",
|
||||
"@next/swc-darwin-x64": "16.0.6",
|
||||
"@next/swc-linux-arm64-gnu": "16.0.6",
|
||||
"@next/swc-linux-arm64-musl": "16.0.6",
|
||||
"@next/swc-linux-x64-gnu": "16.0.6",
|
||||
"@next/swc-linux-x64-musl": "16.0.6",
|
||||
"@next/swc-win32-arm64-msvc": "16.0.6",
|
||||
"@next/swc-win32-x64-msvc": "16.0.6",
|
||||
"@next/swc-darwin-arm64": "16.0.10",
|
||||
"@next/swc-darwin-x64": "16.0.10",
|
||||
"@next/swc-linux-arm64-gnu": "16.0.10",
|
||||
"@next/swc-linux-arm64-musl": "16.0.10",
|
||||
"@next/swc-linux-x64-gnu": "16.0.10",
|
||||
"@next/swc-linux-x64-musl": "16.0.10",
|
||||
"@next/swc-win32-arm64-msvc": "16.0.10",
|
||||
"@next/swc-win32-x64-msvc": "16.0.10",
|
||||
"sharp": "^0.34.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -7223,6 +7424,18 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nth-check": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@@ -7426,6 +7639,55 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
|
||||
"integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"entities": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5-htmlparser2-tree-adapter": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
|
||||
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domhandler": "^5.0.3",
|
||||
"parse5": "^7.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5-parser-stream": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
|
||||
"integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parse5": "^7.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5/node_modules/entities": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
||||
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -7950,6 +8212,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
@@ -8698,6 +8966,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "7.22.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz",
|
||||
"integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.18.1"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
@@ -8868,6 +9145,28 @@
|
||||
"d3-timer": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-encoding": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
||||
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
||||
"deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iconv-lite": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-mimetype": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
||||
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
Reference in New Issue
Block a user