feat: update FAQ block

- Modified the FAQ section in both English and Chinese JSON files to enhance user support with clearer descriptions and additional contact information.
- Updated the layout of the PricingPage to include the FAQs component, improving information accessibility.
- Introduced new components for the hero section and pricing table, enhancing the overall user experience and engagement.
- Refactored the pricing layout to streamline the presentation of pricing options and improve maintainability.
This commit is contained in:
javayhu 2025-04-12 19:55:27 +08:00
parent c43d423aa3
commit fd11648d98
11 changed files with 59 additions and 67 deletions

View File

@ -36,8 +36,7 @@
"description": "Make AI SaaS in days, simply and effortlessly",
"faqs": {
"title": "Frequently Asked Questions",
"description": "Can't find what you're looking for?",
"contact": "Contact our customer support team",
"description": "Please feel free to contact us if you have any questions",
"items": {
"item-1": {
"question": "Do you offer a free trial?",
@ -54,6 +53,10 @@
"item-4": {
"question": "What is the refund policy?",
"answer": "We offer a 30-day money-back guarantee if you are not happy with our product."
},
"item-5": {
"question": "Can't find what you're looking for?",
"answer": "Please contact our customer support team at support@mksaas.com"
}
}
}

View File

@ -36,8 +36,7 @@
"description": "使用 MkSaaS 在几天内轻松构建您的 AI SaaS",
"faqs": {
"title": "常见问题",
"description": "找不到您想问的问题?",
"contact": "请联系我们的客户支持团队",
"description": "如果您有任何问题,请随时联系我们",
"items": {
"item-1": {
"question": "你们提供免费试用吗?",
@ -54,6 +53,10 @@
"item-4": {
"question": "你们的退款政策是什么?",
"answer": "是的我们提供30天的退款保证。"
},
"item-5": {
"question": "找不到您想问的问题?",
"answer": "请联系我们的客户支持团队邮箱地址support@mksaas.com"
}
}
}

View File

@ -1,3 +1,4 @@
import FAQs from '@/components/blocks/faqs/faqs';
import { constructMetadata } from '@/lib/metadata';
import { getBaseUrlWithLocale } from '@/lib/urls/urls';
import { Metadata } from 'next';
@ -5,7 +6,6 @@ import { Locale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
import CallToAction from '../../preview/call-to-action/one/page';
import ContentSection from '../../preview/content/one/page';
import FAQs from '../../preview/faqs/one/page';
import Features from '../../preview/features/one/page';
import HeroSection from '../../preview/hero-section/one/page';
import LogoCloud from '../../preview/logo-cloud/one/page';

View File

@ -1,5 +1,3 @@
import FAQs from '@/components/blocks/faqs/faqs';
import Container from '@/components/layout/container';
import { constructMetadata } from '@/lib/metadata';
import { getBaseUrlWithLocale } from '@/lib/urls/urls';
import { Metadata } from 'next';
@ -41,11 +39,7 @@ export default async function PricingPageLayout({
</div>
</div>
<Container className="mt-8 px-4 flex flex-col gap-16">
{children}
<FAQs />
</Container>
{children}
</div>
);
}

View File

@ -1,10 +1,13 @@
import FAQs from '@/components/blocks/faqs/faqs';
import Container from '@/components/layout/container';
import { PricingTable } from '@/components/payment/pricing-table';
import { PricingTable } from '@/components/pricing/pricing-table';
export default async function PricingPage() {
return (
<Container className="mt-8 px-4 max-w-6xl">
<Container className="mt-8 max-w-6xl px-4 flex flex-col gap-16">
<PricingTable />
<FAQs />
</Container>
);
}

View File

@ -6,10 +6,8 @@ import {
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion';
import { getUrlWithLocale } from '@/lib/urls/urls';
import { DynamicIcon, type IconName } from 'lucide-react/dynamic';
import { IconName } from 'lucide-react/dynamic';
import { useLocale, useTranslations } from 'next-intl';
import Link from 'next/link';
type FAQItem = {
id: string;
@ -47,58 +45,49 @@ export default function FAQs() {
question: t('items.item-4.question'),
answer: t('items.item-4.answer'),
},
{
id: 'item-5',
icon: 'mail',
question: t('items.item-5.question'),
answer: t('items.item-5.answer'),
},
];
return (
<section className="py-16">
<div className="mx-auto max-w-5xl px-4 md:px-6">
<div className="flex flex-col gap-10 md:flex-row md:gap-16">
<div className="md:w-1/3">
<div className="sticky top-20">
<h2 className="mt-4 text-3xl font-bold">
{t('title')}
</h2>
<p className="text-muted-foreground mt-4 text-sm">
{t('description')}
</p>
<p className="text-muted-foreground mt-2 text-sm">
<Link
href={getUrlWithLocale('/contact', locale)}
className="text-primary font-medium hover:underline"
>
{t('contact')}
</Link>
</p>
</div>
</div>
<div className="md:w-2/3">
<Accordion type="single" collapsible className="w-full space-y-2">
{faqItems.map((item) => (
<AccordionItem
key={item.id}
value={item.id}
className="bg-background shadow-xs rounded-lg border px-4 last:border-b"
>
<AccordionTrigger className="cursor-pointer items-center py-5 hover:no-underline">
<div className="flex items-center gap-3">
<div className="flex size-6">
<DynamicIcon
name={item.icon}
className="m-auto size-4"
/>
</div>
<span className="text-base">{item.question}</span>
</div>
</AccordionTrigger>
<AccordionContent className="pb-5">
<div className="px-9">
<p className="text-base">{item.answer}</p>
</div>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
<div className="mx-auto max-w-xl text-center">
<h2 className="text-balance text-3xl font-bold tracking-tight">
{t('title')}
</h2>
<p className="text-muted-foreground mt-4 text-balance text-lg">
{t('description')}
</p>
</div>
<div className="mx-auto max-w-5xl mt-12">
<Accordion
type="single"
collapsible
className="bg-card ring-muted w-full rounded-2xl border px-8 py-3 shadow-sm ring-4 dark:ring-0"
>
{faqItems.map((item) => (
<AccordionItem
key={item.id}
value={item.id}
className="border-dashed"
>
<AccordionTrigger className="cursor-pointer text-base hover:no-underline">
{item.question}
</AccordionTrigger>
<AccordionContent>
<p className="text-base text-muted-foreground">
{item.answer}
</p>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</div>
</section>

View File

@ -3,12 +3,12 @@
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { useCurrentUser } from '@/hooks/use-current-user';
import { useLocalePathname } from '@/i18n/navigation';
import { formatPrice } from '@/lib/formatter';
import { cn } from '@/lib/utils';
import { PaymentType, PaymentTypes, PlanInterval, PlanIntervals, Price, PricePlan } from '@/payment/types';
import { Check, CheckCircleIcon, XCircleIcon } from 'lucide-react';
import { CheckCircleIcon, XCircleIcon } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useLocalePathname } from '@/i18n/navigation';
import { LoginWrapper } from '../auth/login-wrapper';
import { CheckoutButton } from './create-checkout-button';

View File

@ -1,6 +1,6 @@
'use client';
import { CustomerPortalButton } from '@/components/payment/customer-portal-button';
import { CustomerPortalButton } from '@/components/pricing/customer-portal-button';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';