From 57185e174d947f3d4accb0fd16f951367470900c Mon Sep 17 00:00:00 2001 From: Kunthawat Date: Sat, 11 Apr 2026 08:43:08 +0700 Subject: [PATCH] Initial commit: Next.js + Payload CMS for moreminimore-redesign - Next.js 16 App Router + Payload CMS 3.82 - PostgreSQL via @payloadcms/db-postgres - All pages: Home, Services (4), About, Portfolio, Blog, Contact, FAQ - PDPA: CookieBanner, ConsentLogs API, Privacy Policy, Terms, Cookie Policy - SEO: sitemap, robots.txt, metadata exports, JSON-LD --- .dockerignore | 9 + .env.example | 17 + Dockerfile | 39 ++ docker-compose.yml | 40 ++ next.config.ts | 31 + package.json | 45 ++ src/app/(frontend)/about-us/page.tsx | 291 +++++++++ src/app/(frontend)/api/consent/route.ts | 65 ++ src/app/(frontend)/blog/[slug]/page.tsx | 310 +++++++++ src/app/(frontend)/blog/page.tsx | 188 ++++++ src/app/(frontend)/contact-us/layout.tsx | 31 + src/app/(frontend)/contact-us/page.tsx | 320 +++++++++ src/app/(frontend)/cookie-policy/page.tsx | 222 +++++++ src/app/(frontend)/faq/layout.tsx | 31 + src/app/(frontend)/faq/page.tsx | 200 ++++++ src/app/(frontend)/globals.css | 130 ++++ src/app/(frontend)/layout.tsx | 82 +++ src/app/(frontend)/page.tsx | 449 +++++++++++++ src/app/(frontend)/portfolio/layout.tsx | 31 + src/app/(frontend)/portfolio/page.tsx | 321 +++++++++ src/app/(frontend)/privacy-policy/page.tsx | 249 +++++++ .../services/ai-automation/layout.tsx | 31 + .../services/ai-automation/page.tsx | 511 +++++++++++++++ .../services/marketing-automation/layout.tsx | 31 + .../services/marketing-automation/page.tsx | 609 ++++++++++++++++++ .../services/tech-consult/layout.tsx | 31 + .../(frontend)/services/tech-consult/page.tsx | 600 +++++++++++++++++ .../services/web-development/layout.tsx | 31 + .../services/web-development/page.tsx | 604 +++++++++++++++++ src/app/(frontend)/terms-of-service/page.tsx | 323 ++++++++++ .../(payload)/admin/[[...segments]]/page.tsx | 23 + src/app/(payload)/admin/importMap.js | 2 + src/app/(payload)/api/[[...slug]]/route.ts | 18 + .../(payload)/api/graphql-playground/route.ts | 6 + src/app/(payload)/api/graphql/route.ts | 6 + src/app/(payload)/custom.scss | 1 + src/app/(payload)/layout.tsx | 30 + src/app/robots.ts | 12 + src/app/sitemap.ts | 88 +++ src/collections/ConsentLogs.ts | 79 +++ src/collections/Media.ts | 16 + src/collections/Portfolio.ts | 56 ++ src/collections/Posts.ts | 73 +++ src/collections/Users.ts | 12 + src/components/CookieBanner.tsx | 137 ++++ src/components/Footer.tsx | 89 +++ src/components/Navigation.tsx | 121 ++++ src/index.ts | 1 + src/payload.config.ts | 43 ++ tsconfig.json | 28 + tsconfig.tsbuildinfo | 1 + 51 files changed, 6714 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 next.config.ts create mode 100644 package.json create mode 100644 src/app/(frontend)/about-us/page.tsx create mode 100644 src/app/(frontend)/api/consent/route.ts create mode 100644 src/app/(frontend)/blog/[slug]/page.tsx create mode 100644 src/app/(frontend)/blog/page.tsx create mode 100644 src/app/(frontend)/contact-us/layout.tsx create mode 100644 src/app/(frontend)/contact-us/page.tsx create mode 100644 src/app/(frontend)/cookie-policy/page.tsx create mode 100644 src/app/(frontend)/faq/layout.tsx create mode 100644 src/app/(frontend)/faq/page.tsx create mode 100644 src/app/(frontend)/globals.css create mode 100644 src/app/(frontend)/layout.tsx create mode 100644 src/app/(frontend)/page.tsx create mode 100644 src/app/(frontend)/portfolio/layout.tsx create mode 100644 src/app/(frontend)/portfolio/page.tsx create mode 100644 src/app/(frontend)/privacy-policy/page.tsx create mode 100644 src/app/(frontend)/services/ai-automation/layout.tsx create mode 100644 src/app/(frontend)/services/ai-automation/page.tsx create mode 100644 src/app/(frontend)/services/marketing-automation/layout.tsx create mode 100644 src/app/(frontend)/services/marketing-automation/page.tsx create mode 100644 src/app/(frontend)/services/tech-consult/layout.tsx create mode 100644 src/app/(frontend)/services/tech-consult/page.tsx create mode 100644 src/app/(frontend)/services/web-development/layout.tsx create mode 100644 src/app/(frontend)/services/web-development/page.tsx create mode 100644 src/app/(frontend)/terms-of-service/page.tsx create mode 100644 src/app/(payload)/admin/[[...segments]]/page.tsx create mode 100644 src/app/(payload)/admin/importMap.js create mode 100644 src/app/(payload)/api/[[...slug]]/route.ts create mode 100644 src/app/(payload)/api/graphql-playground/route.ts create mode 100644 src/app/(payload)/api/graphql/route.ts create mode 100644 src/app/(payload)/custom.scss create mode 100644 src/app/(payload)/layout.tsx create mode 100644 src/app/robots.ts create mode 100644 src/app/sitemap.ts create mode 100644 src/collections/ConsentLogs.ts create mode 100644 src/collections/Media.ts create mode 100644 src/collections/Portfolio.ts create mode 100644 src/collections/Posts.ts create mode 100644 src/collections/Users.ts create mode 100644 src/components/CookieBanner.tsx create mode 100644 src/components/Footer.tsx create mode 100644 src/components/Navigation.tsx create mode 100644 src/index.ts create mode 100644 src/payload.config.ts create mode 100644 tsconfig.json create mode 100644 tsconfig.tsbuildinfo diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6e447ed --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +node_modules +.next +out +dist +build +*.log +.env*.local +.DS_Store +*.pem diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..00a15c7 --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +# Payload CMS +PAYLOAD_SECRET=your-super-secret-key-change-in-production +DATABASE_URL=postgresql://payload:payloadpass@localhost:5432/payload + +# Server +NEXT_PUBLIC_SERVER_URL=http://localhost:3000 + +# Analytics (PDPA - require consent) +NEXT_PUBLIC_GA4_ID=G-XXXXXXXXXX +NEXT_PUBLIC_UMAMI_ID=b2e87a6c-0b64-43c8-bb09-e406ffca0af1 + +# Contact form (optional) +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USER=your-email@gmail.com +SMTP_PASS=your-app-password +CONTACT_EMAIL=contact@moreminimore.com diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a3cf7d7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +# Multi-stage Dockerfile for Next.js + Payload CMS with PostgreSQL +# Requires `output: 'standalone'` in next.config.ts + +FROM node:22-alpine AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +COPY package.json pnpm-lock.yaml* ./ +RUN corepack enable && corepack prepare pnpm@9.0.0 --activate && pnpm install --frozen-lockfile + +FROM deps AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +RUN pnpm build + +FROM node:22-alpine AS runner +WORKDIR /app + +ENV NODE_ENV production + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +RUN mkdir .next +RUN chown nextjs:nodejs .next + +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder --chown=nextjs:nodejs /app/public ./public + +USER nextjs + +EXPOSE 3000 +ENV PORT 3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["node", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..04848e7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,40 @@ +version: '3' + +services: + payload: + image: node:22-alpine + ports: + - '3000:3000' + volumes: + - .:/home/node/app + - node_modules:/home/node/app/node_modules + working_dir: /home/node/app/ + command: sh -c "corepack enable && corepack prepare pnpm@9.0.0 --activate && pnpm install && pnpm dev" + depends_on: + - postgres + env_file: + - .env + networks: + - payload-network + + postgres: + restart: always + image: postgres:16-alpine + volumes: + - pgdata:/var/lib/postgresql/data + ports: + - '5432:5432' + environment: + POSTGRES_USER: payload + POSTGRES_PASSWORD: payloadpass + POSTGRES_DB: payload + networks: + - payload-network + +networks: + payload-network: + driver: bridge + +volumes: + pgdata: + node_modules: diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..e08803f --- /dev/null +++ b/next.config.ts @@ -0,0 +1,31 @@ +import { withPayload } from '@payloadcms/next/withPayload' +import type { NextConfig } from 'next' +import path from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(__filename) + +const nextConfig: NextConfig = { + images: { + localPatterns: [ + { + pathname: '/api/media/file/**', + }, + ], + }, + output: 'standalone', + webpack: (webpackConfig) => { + webpackConfig.resolve.extensionAlias = { + '.cjs': ['.cts', '.cjs'], + '.js': ['.ts', '.tsx', '.js', '.jsx'], + '.mjs': ['.mts', '.mjs'], + } + return webpackConfig + }, + turbopack: { + root: path.resolve(dirname), + }, +} + +export default withPayload(nextConfig, { devBundleServerPackages: false }) diff --git a/package.json b/package.json new file mode 100644 index 0000000..ef69127 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "nextjs-payload-starter", + "version": "1.0.0", + "description": "Next.js + Payload CMS starter template with PostgreSQL", + "private": true, + "type": "module", + "scripts": { + "dev": "cross-env NODE_OPTIONS=--no-deprecation next dev", + "devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev", + "build": "cross-env NODE_OPTIONS=--no-deprecation next build", + "start": "cross-env NODE_OPTIONS=--no-deprecation next start", + "payload": "cross-env NODE_OPTIONS=--no-deprecation payload", + "generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap", + "generate:types": "cross-env NODE_OPTIONS=--no-deprecation payload generate:types", + "lint": "cross-env NODE_OPTIONS=--no-deprecation next lint", + "docker:dev": "docker compose up -d", + "docker:dev:logs": "docker compose logs -f", + "docker:down": "docker compose down" + }, + "dependencies": { + "@payloadcms/next": "^3.82.1", + "@payloadcms/richtext-lexical": "^3.82.1", + "@payloadcms/ui": "^3.82.1", + "@payloadcms/db-postgres": "^3.82.1", + "cross-env": "^7.0.3", + "graphql": "^16.8.1", + "next": "^16.2.3", + "payload": "^3.82.1", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "sharp": "^0.34.2" + }, + "devDependencies": { + "@types/node": "^22.19.9", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "eslint": "^9.16.0", + "eslint-config-next": "^16.2.3", + "prettier": "^3.4.2", + "typescript": "^5.7.3" + }, + "engines": { + "node": "^18.20.2 || >=20.9.0" + } +} diff --git a/src/app/(frontend)/about-us/page.tsx b/src/app/(frontend)/about-us/page.tsx new file mode 100644 index 0000000..b84699a --- /dev/null +++ b/src/app/(frontend)/about-us/page.tsx @@ -0,0 +1,291 @@ +import type { Metadata } from 'next' +import Link from 'next/link' + +export const metadata: Metadata = { + title: 'บริษัท มอร์มินิมอร์ จำกัด - รับทำเว็บไซต์ AI Chatbot และ Marketing Automation', + description: 'บริษัท มอร์มินิมอร์ จำกัด ให้บริการรับทำเว็บไซต์ SEO AI Chatbot และระบบอัตโนมัติทางการตลาดสำหรับ SMEs ไทย', + keywords: 'รับทำเว็บไซต์, AI Chatbot, Marketing Automation, SEO, สมุทรสาคร, SMEs ไทย', + openGraph: { + title: 'บริษัท มอร์มินิมอร์ จำกัด - รับทำเว็บไซต์ AI Chatbot และ Marketing Automation', + description: 'บริษัท มอร์มินิมอร์ จำกัด ให้บริการรับทำเว็บไซต์ SEO AI Chatbot และระบบอัตโนมัติทางการตลาดสำหรับ SMEs ไทย', + url: 'https://moreminimore.com/about-us', + siteName: 'MoreminiMore', + locale: 'th_TH', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'บริษัท มอร์มินิมอร์ จำกัด - รับทำเว็บไซต์ AI Chatbot และ Marketing Automation', + description: 'บริษัท มอร์มินิมอร์ จำกัด ให้บริการรับทำเว็บไซต์ SEO AI Chatbot และระบบอัตโนมัติทางการตลาดสำหรับ SMEs ไทย', + }, + alternates: { + canonical: 'https://moreminimore.com/about-us', + }, +} + +export default function AboutUsPage() { + return ( +
+ {/* Hero Section */} +
+ {/* Floating Shapes */} +
+
+
+ + {/* Grid Pattern */} +
+ +
+
+

+ เกี่ยวกับเรา +

+

+ มอร์มินิมอร์ — พาร์ทเนอร์ด้าน IT และ AI ที่พร้อมเติบโตไปกับคุณ +

+
+
+
+ + {/* Vision Section */} +
+
+
+
+ + + วิสัยทัศน์ + +

+ เติบโตไปด้วยกัน +

+
+ +
+

+ "เราเชื่อว่าความสำเร็จของลูกค้าคือความสำเร็จของเรา
+ เมื่อธุรกิจของคุณเติบโต เราก็เติบโตไปด้วยกัน" +

+

+ ความสำเร็จที่แท้จริงไม่ใช่แค่ตัวเลข แต่คือการเห็นผลงานที่เกิดขึ้นจริงของลูกค้า +

+
+
+
+
+ + {/* Values Section */} +
+
+
+ + + ค่านิยม + +

+ สิ่งที่เรายึดมั่น +

+

+ เรามุ่งเน้นที่ผลลัพธ์ที่จับต้องได้ ไม่ใช่แค่ตัวเลขบนหน้าจอ +

+
+ +
+ {/* Value 1 */} +
+
+ +
+

เน้นผลงานจริง

+

+ เราวัดความสำเร็จจากยอดขายที่เพิ่มขึ้นของลูกค้า ไม่ใช่แค่คะแนน SEO หรือจำนวนการเข้าชม +

+
+ + {/* Value 2 */} +
+
+ +
+

เป็นพาร์ทเนอร์

+

+ เราไม่ได้มองลูกค้าเป็นแค่ผู้จ้าง แต่มองเป็นพาร์ทเนอร์ที่จะเติบโตไปด้วยกันในระยะยาว +

+
+ + {/* Value 3 */} +
+
+ +
+

คุ้มค่าที่สุด

+

+ ออกแบบโซลูชันให้เหมาะกับงบประมาณของคุณ เริ่มต้นง่าย ไม่ต้องลงทุนมาก +

+
+ + {/* Value 4 */} +
+
+ +
+

ทำงานเร็ว

+

+ เข้าใจว่าธุรกิจต้องการผลลัพธ์เร็ว ทำงานตรงเวลา ไม่ผัดวันประงัน +

+
+ + {/* Value 5 */} +
+
+ +
+

ดูแลต่อเนื่อง

+

+ ไม่ทิ้งหลังขาย พร้อมสนับสนุนและปรับปรุงระบบให้ตลอดเวลา +

+
+ + {/* Value 6 */} +
+
+ +
+

โปร่งใส

+

+ ราคาชัดเจน ไม่มีค่าใช้จ่ายซ่อนเร้น รายงานผลตรง ชัดเจน +

+
+
+
+
+ + {/* Why Choose Us */} +
+
+
+

+ ทำไมเลือกเรา? +

+ +
+
+
+ +
+

เน้นผลลัพธ์

+

เราวัดผลทุกอย่าง และมุ่งเน้นให้เห็นผลจริงในการเพิ่มยอดขาย

+
+ +
+
+ +
+

ราคาเหมาะสม

+

ออกแบบมาให้ SMEs สามารถเริ่มต้นได้ง่าย ไม่ต้องลงทุนมาก

+
+ +
+
+ +
+

ดูแลต่อเนื่อง

+

ไม่ทิ้งหลังขาย พร้อมอบรมและสนับสนุนตลอดการใช้งาน

+
+ +
+
+ +
+

ทำงานเร็ว

+

เข้าใจว่าธุรกิจต้องการผลลัพธ์เร็ว ทำงานตรงเวลา ไม่ผัดวัน

+
+
+
+
+
+ + {/* Company Info */} +
+
+
+

ข้อมูลบริษัท

+
+
+
+

บริษัท มอร์มินิมอร์ จำกัด

+ +
+
+

บริการของเรา

+
    +
  • + + รับทำเว็บไซต์ +
  • +
  • + + AI Chatbot +
  • +
  • + + Marketing Automation +
  • +
  • + + SEO ติดอันดับ Google +
  • +
  • + + ที่ปรึกษาด้านเทคโนโลยี +
  • +
+
+
+
+
+
+
+ + {/* CTA Section */} +
+
+

+ พร้อมร่วมงานกับคุณแล้วหรือยัง? +

+

+ เริ่มต้นง่ายๆ แค่โทรหาหรือเพิ่ม LINE มาคุยกันก่อน ไม่มีค่าใช้จ่าย! +

+
+ + + + + 080-995-5945 + + + + + + เพิ่ม Line + +
+
+
+
+ ) +} diff --git a/src/app/(frontend)/api/consent/route.ts b/src/app/(frontend)/api/consent/route.ts new file mode 100644 index 0000000..d0d3537 --- /dev/null +++ b/src/app/(frontend)/api/consent/route.ts @@ -0,0 +1,65 @@ +import { NextRequest, NextResponse } from 'next/server' +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function POST(request: NextRequest) { + try { + const body = await request.json() + + const { + action, + purpose, + analytics, + marketing, + functional, + previousConsent, + newConsent, + } = body + + // Get IP address + const ip = request.headers.get('x-forwarded-for')?.split(',')[0] || + request.headers.get('x-real-ip') || + 'unknown' + + // Get User Agent + const userAgent = request.headers.get('user-agent') || 'unknown' + + // Get Payload CMS instance + const payload = await getPayload({ config }) + + // Create consent log document + const doc = await payload.create({ + collection: 'consent-logs', + data: { + action: action || 'update', + purpose: purpose || 'all', + analytics: analytics || false, + marketing: marketing || false, + functional: functional ?? true, + userAgent, + ip, + timestamp: new Date().toISOString(), + previousConsent: previousConsent || null, + newConsent: newConsent || null, + }, + }) + + return NextResponse.json({ + success: true, + doc, + }) + } catch (error) { + console.error('Error creating consent log:', error) + return NextResponse.json( + { success: false, error: 'Failed to create consent log' }, + { status: 500 } + ) + } +} + +export async function GET() { + return NextResponse.json( + { error: 'Method not allowed. Use POST to submit consent.' }, + { status: 405 } + ) +} diff --git a/src/app/(frontend)/blog/[slug]/page.tsx b/src/app/(frontend)/blog/[slug]/page.tsx new file mode 100644 index 0000000..d204e07 --- /dev/null +++ b/src/app/(frontend)/blog/[slug]/page.tsx @@ -0,0 +1,310 @@ +import { Metadata } from 'next' +import { notFound } from 'next/navigation' +import Link from 'next/link' +import { getPayload } from 'payload' +import config from '@payload-config' + +export const dynamic = 'force-dynamic' + +interface PageProps { + params: Promise<{ + slug: string + }> +} + +async function getPost(slug: string) { + try { + const payload = await getPayload({ config }) + const result = await payload.find({ + collection: 'posts', + where: { + slug: { + equals: slug, + }, + }, + depth: 2, + }) + return result.docs[0] || null + } catch (error) { + console.error('Error fetching post:', error) + return null + } +} + +async function getRelatedPosts(currentPostId: string | number, category?: string) { + try { + const payload = await getPayload({ config }) + const result = await payload.find({ + collection: 'posts', + where: category ? { + and: [ + { + id: { + not_equals: currentPostId, + }, + }, + { + category: { + equals: category, + }, + }, + ], + } : { + id: { + not_equals: currentPostId, + }, + }, + limit: 3, + depth: 1, + }) + return result.docs + } catch (error) { + console.error('Error fetching related posts:', error) + return [] + } +} + +export async function generateMetadata({ params }: PageProps): Promise { + const { slug } = await params + const post = await getPost(slug) + + if (!post) { + return { + title: 'ไม่พบบทความ | MoreminiMore', + } + } + + const title = typeof post.title === 'string' ? post.title : 'บทความ' + const description = typeof post.description === 'string' ? post.description : '' + + return { + title: `${title} | MoreminiMore`, + description, + openGraph: { + title: `${title} | MoreminiMore`, + description, + type: 'article', + }, + } +} + +export default async function BlogPostPage({ params }: PageProps) { + const { slug } = await params + const post = await getPost(slug) + + if (!post) { + notFound() + } + + const category = typeof post.category === 'string' ? post.category : undefined + const relatedPosts = await getRelatedPosts(post.id, category) + + const title = typeof post.title === 'string' ? post.title : 'บทความ' + const description = typeof post.description === 'string' ? post.description : '' + const content = typeof post.content === 'string' ? post.content : '' + const author = typeof post.author === 'object' && post.author !== null ? (post.author as { name?: string }).name : 'ทีมงาน MoreminiMore' + const publishedDate = post.publishedDate ? new Date(post.publishedDate) : new Date() + + return ( + <> + {/* Hero Section */} +
+
+
+
+
+ +
+
+ {/* Breadcrumb */} + + + {category && ( + + {category} + + )} + +

+ {title} +

+ + {/* Meta Info */} +
+ + + + + {author} + + + + + + {publishedDate.toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })} + +
+
+
+
+ + {/* Content Section */} +
+
+
+ {/* Featured Image Placeholder */} +
+
+ + + +
+
+ + {/* Article Content */} +
+
+ {content.split('\n').map((paragraph, index) => { + const trimmed = paragraph.trim() + if (!trimmed) return
+ + // Headers + if (trimmed.startsWith('# ')) { + return

{trimmed.slice(2)}

+ } + if (trimmed.startsWith('## ')) { + return

{trimmed.slice(3)}

+ } + if (trimmed.startsWith('### ')) { + return

{trimmed.slice(4)}

+ } + + // Bold text + if (trimmed.startsWith('**') && trimmed.endsWith('**')) { + return

{trimmed.slice(2, -2)}

+ } + + // List items + if (trimmed.startsWith('- ')) { + return
  • {trimmed.slice(2)}
  • + } + + // Regular paragraphs - check for inline bold + const parts = trimmed.split(/(\*\*[^*]+\*\*)/g) + if (parts.length > 1) { + return ( +

    + {parts.map((part, i) => { + if (part.startsWith('**') && part.endsWith('**')) { + return {part.slice(2, -2)} + } + return part + })} +

    + ) + } + + return

    {trimmed}

    + })} +
    +
    + + {/* Tags */} + {post.tags && Array.isArray(post.tags) && post.tags.length > 0 && ( +
    +
    + {post.tags.map((tag, index) => ( + + #{typeof tag === 'string' ? tag : String(tag)} + + ))} +
    +
    + )} +
    +
    +
    + + {/* Related Posts Section */} + {relatedPosts.length > 0 && ( + + )} + + {/* Back to Blog CTA */} +
    +
    + + + + + กลับไปหน้าบล็อก + +
    +
    + + ) +} diff --git a/src/app/(frontend)/blog/page.tsx b/src/app/(frontend)/blog/page.tsx new file mode 100644 index 0000000..865db1a --- /dev/null +++ b/src/app/(frontend)/blog/page.tsx @@ -0,0 +1,188 @@ +import { Metadata } from 'next' +import Link from 'next/link' +import { getPayload } from 'payload' +import config from '@payload-config' + +export const metadata: Metadata = { + title: 'บล็อก | MoreminiMore - ความรู้เรื่อง AI และ Digital Marketing', + description: 'บทความและความรู้เรื่อง AI, SEO, Marketing Automation และเทคโนโลยีสำหรับ SMEs ไทย', + keywords: 'บล็อก, AI, SEO, Marketing Automation, Digital Marketing, SMEs ไทย', + openGraph: { + title: 'บล็อก | MoreminiMore - ความรู้เรื่อง AI และ Digital Marketing', + description: 'บทความและความรู้เรื่อง AI, SEO, Marketing Automation และเทคโนโลยีสำหรับ SMEs ไทย', + url: 'https://moreminimore.com/blog', + siteName: 'MoreminiMore', + locale: 'th_TH', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'บล็อก | MoreminiMore - ความรู้เรื่อง AI และ Digital Marketing', + description: 'บทความและความรู้เรื่อง AI, SEO, Marketing Automation และเทคโนโลยีสำหรับ SMEs ไทย', + }, + alternates: { + canonical: 'https://moreminimore.com/blog', + }, +} + +async function getPosts() { + try { + const payload = await getPayload({ config }) + const posts = await payload.find({ + collection: 'posts', + depth: 1, + limit: 100, + }) + return posts.docs + } catch (error) { + console.error('Error fetching posts:', error) + return [] + } +} + +export default async function BlogPage() { + const posts = await getPosts() + + return ( + <> + {/* Hero Section */} +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +

    + บล็อกของเรา +

    +

    + ความรู้และข่าวสารเกี่ยวกับ AI, การตลาดอัตโนมัติ และการพัฒนาธุรกิจ +

    +
    +
    +
    + + {/* Blog Grid Section */} +
    +
    + {posts.length === 0 ? ( +
    + + + +

    ยังไม่มีบทความ

    +

    กรุณากลับมาเยี่ยมชมใหม่ในเร็วๆ นี้

    +
    + ) : ( +
    + {posts.map((post, index) => ( +
    + {/* Featured Image Placeholder */} +
    +
    + + + +
    + {/* Category Badge */} + {post.category && ( + + {post.category} + + )} +
    + + {/* Content */} +
    +

    + {typeof post.title === 'string' ? post.title : 'Untitled'} +

    +

    + {typeof post.description === 'string' ? post.description : ''} +

    + + {/* Meta Info */} +
    + {post.author && ( + + + + + {typeof post.author === 'object' && post.author !== null ? (post.author as { name?: string }).name || 'ทีมงาน MoreminiMore' : 'ทีมงาน MoreminiMore'} + + )} + {post.publishedDate && ( + + + + + {new Date(post.publishedDate).toLocaleDateString('th-TH', { year: 'numeric', month: 'short', day: 'numeric' })} + + )} +
    + + {/* Read More Link */} + + อ่านเพิ่มเติม + + + + +
    +
    + ))} +
    + )} +
    +
    + + {/* CTA Section */} +
    +
    +
    +

    + อยากรู้ว่า AI ช่วยธุรกิจคุณได้อย่างไร? +

    +

    + ปรึกษาฟรี! เราพร้อมวิเคราะห์และแนะนำโซลูชันที่เหมาะกับธุรกิจของคุณ +

    +
    + + + + + ปรึกษาฟรี + + + + + + 080-995-5945 + +
    +
    +
    +
    + + ) +} diff --git a/src/app/(frontend)/contact-us/layout.tsx b/src/app/(frontend)/contact-us/layout.tsx new file mode 100644 index 0000000..9dcac97 --- /dev/null +++ b/src/app/(frontend)/contact-us/layout.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'ติดต่อเรา | MoreminiMore - ปรึกษาฟรี ไม่มีค่าใช้จ่าย', + description: 'ติดต่อบริษัท มอร์มินิมอร์ จำกัด ปรึกษาฟรี ไม่มีค่าใช้จ่าย โทร 080-995-5945', + keywords: 'ติดต่อ, ปรึกษา, LINE, โทรศัพท์, อีเมล, MoreminiMore', + openGraph: { + title: 'ติดต่อเรา | MoreminiMore - ปรึกษาฟรี ไม่มีค่าใช้จ่าย', + description: 'ติดต่อบริษัท มอร์มินิมอร์ จำกัด ปรึกษาฟรี ไม่มีค่าใช้จ่าย โทร 080-995-5945', + url: 'https://moreminimore.com/contact-us', + siteName: 'MoreminiMore', + locale: 'th_TH', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'ติดต่อเรา | MoreminiMore - ปรึกษาฟรี ไม่มีค่าใช้จ่าย', + description: 'ติดต่อบริษัท มอร์มินิมอร์ จำกัด ปรึกษาฟรี ไม่มีค่าใช้จ่าย โทร 080-995-5945', + }, + alternates: { + canonical: 'https://moreminimore.com/contact-us', + }, +} + +export default function ContactUsLayout({ + children, +}: { + children: React.ReactNode +}) { + return children +} diff --git a/src/app/(frontend)/contact-us/page.tsx b/src/app/(frontend)/contact-us/page.tsx new file mode 100644 index 0000000..65c73b4 --- /dev/null +++ b/src/app/(frontend)/contact-us/page.tsx @@ -0,0 +1,320 @@ +'use client' + +import { useState } from 'react' +import Link from 'next/link' + +export default function ContactUsPage() { + const [formData, setFormData] = useState({ + name: '', + email: '', + phone: '', + company: '', + message: '', + }) + const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle') + + const handleChange = (e: React.ChangeEvent) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }) + } + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setStatus('loading') + + try { + // In a real implementation, this would submit to an API endpoint + // For now, we simulate a successful submission + await new Promise(resolve => setTimeout(resolve, 1000)) + + // Simulate API call + // await fetch('/api/contact', { + // method: 'POST', + // headers: { 'Content-Type': 'application/json' }, + // body: JSON.stringify(formData), + // }) + + setStatus('success') + setFormData({ name: '', email: '', phone: '', company: '', message: '' }) + } catch (error) { + setStatus('error') + } + } + + return ( +
    + {/* Hero Section */} +
    + {/* Floating Shapes */} +
    +
    +
    + + {/* Grid Pattern */} +
    + +
    +
    +

    + ติดต่อเรา +

    +

    + พร้อมให้คำปรึกษาและช่วยเหลือคุณ ติดต่อได้หลายช่องทาง +

    +
    +
    +
    + + {/* Contact Methods */} +
    + +
    + + {/* Contact Form */} +
    +
    +
    +

    ส่งข้อความถึงเรา

    +

    กรอกแบบฟอร์มด้านล่างแล้วเราจะติดต่อกลับโดยเร็วที่สุด

    + + {status === 'success' ? ( +
    + + + +

    ส่งข้อความสำเร็จ!

    +

    ขอบคุณที่ติดต่อเรา เราจะตอบกลับภายใน 24 ชั่วโมง

    + +
    + ) : ( +
    + {status === 'error' && ( +
    +

    เกิดข้อผิดพลาด กรุณาลองอีกครั้ง หรือติดต่อเราทางช่องทางอื่น

    +
    + )} + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    + +
    + + +
    +
    + +
    + + +
    + + + +

    + หรือติดต่อเราโดยตรงที่ contact@moreminimore.com +

    +
    + )} +
    +
    +
    + + {/* Working Hours */} +
    +
    +
    +

    เวลาทำการ

    +
    +
    + จันทร์ - ศุกร์ + 09:00 - 18:00 น. +
    +
    + เสาร์ + 10:00 - 16:00 น. +
    +
    + อาทิตย์ + ปิดทำการ +
    +
    +

    * นอกเหนือเวลาทำการ สามารถติดต่อทาง LINE ได้ตลอด 24 ชั่วโมง

    +
    +
    +
    + + {/* CTA Section */} +
    +
    +

    + พร้อมเริ่มต้นทำงานกับเราแล้วหรือยัง? +

    +

    + ติดต่อเราเพื่อคุยกันและให้คำปรึกษาฟรี! เราพร้อมช่วยเหลือคุณ +

    + +
    +
    +
    + ) +} diff --git a/src/app/(frontend)/cookie-policy/page.tsx b/src/app/(frontend)/cookie-policy/page.tsx new file mode 100644 index 0000000..5c34fca --- /dev/null +++ b/src/app/(frontend)/cookie-policy/page.tsx @@ -0,0 +1,222 @@ +import type { Metadata } from 'next' +import Link from 'next/link' + +export const metadata: Metadata = { + title: 'นโยบายคุกกี้ | MoreminiMore', + description: 'นโยบายการใช้คุกกี้ของเว็บไซต์ moreminimore.com', + keywords: 'นโยบายคุกกี้, Cookie, PDPA, MoreminiMore', + openGraph: { + title: 'นโยบายคุกกี้ | MoreminiMore', + description: 'นโยบายการใช้คุกกี้ของเว็บไซต์ moreminimore.com', + url: 'https://moreminimore.com/cookie-policy', + siteName: 'MoreminiMore', + locale: 'th_TH', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'นโยบายคุกกี้ | MoreminiMore', + description: 'นโยบายการใช้คุกกี้ของเว็บไซต์ moreminimore.com', + }, + alternates: { + canonical: 'https://moreminimore.com/cookie-policy', + }, +} + +export default function CookiePolicyPage() { + return ( +
    + {/* Hero Section */} +
    +
    +

    + นโยบายคุกกี้ +

    + +
    + {/* Document Info */} +
    +

    + ชื่อเว็บไซต์: MoreminiMore
    + ผู้ควบคุมข้อมูล: บริษัท มอร์มินิมอร์ จำกัด
    + มีผลบังคับใช้วันที่: 1 มีนาคม 2569
    + แก้ไขล่าสุด: 1 เมษายน 2569 +

    +
    + + {/* Table of Contents */} + + + {/* Section 1: What are Cookies */} +

    1. คุกกี้คืออะไร?

    +

    + คุกกี้ (Cookies) คือไฟล์ข้อความขนาดเล็กที่เว็บไซต์ส่งไปเก็บไว้ในอุปกรณ์ของท่าน (คอมพิวเตอร์, สมาร์ทโฟน, หรือแท็บเล็ต) เมื่อท่านเข้าชมเว็บไซต์ คุกกี้ช่วยให้เว็บไซต์จดจำการตั้งค่าและการกระทำของท่านได้ +

    +

    + คุกกี้ถูกใช้อย่างแพร่หลายเพื่อปรับปรุงประสบการณ์การใช้งานเว็บไซต์ เช่น จดจำการเข้าสู่ระบบ จดจำสินค้าในตะกร้า หรือปรับแต่งเนื้อหาตามความชอบของท่าน +

    + + {/* Section 2: Types We Use */} +

    2. ประเภทของคุกกี้ที่เราใช้

    +

    + เราใช้คุกกี้หลายประเภทบนเว็บไซต์ของเรา ซึ่งสามารถจำแนกได้ดังนี้: +

    +
      +
    • คุกกี้ที่จำเป็น (Necessary Cookies) - จำเป็นสำหรับการทำงานพื้นฐานของเว็บไซต์
    • +
    • คุกกี้เพื่อประสิทธิภาพ (Performance Cookies) - ช่วยวิเคราะห์และปรับปรุงการทำงานของเว็บไซต์
    • +
    • คุกกี้เพื่อการทำงาน (Functional Cookies) - จดจำการตั้งค่าของท่าน
    • +
    • คุกกี้เพื่อการตลาด (Marketing Cookies) - ติดตามกิจกรรมเพื่อแสดงโฆษณาที่เกี่ยวข้อง
    • +
    + + {/* Section 3: Necessary Cookies */} +

    3. คุกกี้ที่จำเป็น (Necessary Cookies)

    +

    + คุกกี้ที่จำเป็นเป็นคุกกี้ที่ไม่สามารถปิดใช้งานได้ เนื่องจากจำเป็นสำหรับการทำงานพื้นฐานของเว็บไซต์ คุกกี้เหล่านี้ไม่เก็บข้อมูลส่วนบุคคลที่สามารถระบุตัวตนได้ +

    +
    +

    ตัวอย่าง:

    +
      +
    • Session cookies - จดจำการเข้าสู่ระบบ
    • +
    • Security cookies - รักษาความปลอดภัย
    • +
    • load balancing cookies - กระจายภาระการทำงาน
    • +
    +
    +

    + หมายเหตุ: คุกกี้ประเภทนี้ไม่ต้องได้รับความยินยอมจากท่านตามกฎหมาย PDPA เนื่องจากจำเป็นสำหรับการให้บริการที่ท่านร้องขอโดยตรง +

    + + {/* Section 4: Performance Cookies */} +

    4. คุกกี้เพื่อประสิทธิภาพ (Performance Cookies)

    +

    + คุกกี้เพื่อประสิทธิภาพช่วยให้เราเข้าใจว่าผู้เข้าชมใช้งานเว็บไซต์ของเราอย่างไร โดยรวบรวมข้อมูลที่ไม่ระบุตัวตน เช่น หน้าที่เข้าชมบ่อยที่สุด เวลาที่ใช้บนเว็บไซต์ และข้อความแสดงข้อผิดพลาด +

    +
    +

    บริการที่เราใช้:

    +
      +
    • Umami Analytics - ระบบวิเคราะห์เว็บไซต์ที่เน้นความเป็นส่วนตัว (Privacy-focused)
    • +
    • Google Analytics 4 (GA4) - หากท่านให้ความยินยอม
    • +
    +
    +

    + คุกกี้เหล่านี้ ต้องได้รับความยินยอมจากท่านก่อนการใช้งาน ท่านสามารถปฏิเสธได้โดยคลิก "ปฏิเสธทั้งหมด" บนแบนเนอร์คุกกี้ หรือจัดการการตั้งค่าได้ตลอดเวลา +

    + + {/* Section 5: Functional Cookies */} +

    5. คุกกี้เพื่อการทำงาน (Functional Cookies)

    +

    + คุกกี้เพื่อการทำงานช่วยจดจำการตั้งค่าและความชอบของท่าน เช่น ภาษาที่ใช้ ภูมิภาค หรือการกำหนดค่าต่างๆ บนเว็บไซต์ +

    +
    +

    ตัวอย่าง:

    +
      +
    • จดจำการตั้งค่าภาษาไทย/อังกฤษ
    • +
    • จดจำสินค้าที่เคยดู
    • +
    • จดจำการตั้งค่าการแสดงผล
    • +
    +
    +

    + คุกกี้เหล่านี้ ต้องได้รับความยินยอม จากท่านก่อนการใช้งาน +

    + + {/* Section 6: Marketing Cookies */} +

    6. คุกกี้เพื่อการตลาด (Marketing Cookies)

    +

    + คุกกี้เพื่อการตลาดใช้เพื่อติดตามพฤติกรรมการท่องเว็บของท่าน เพื่อแสดงโฆษณาที่เกี่ยวข้องกับความสนใจของท่าน คุกกี้เหล่านี้อาจถูกใช้โดยพันธมิตรด้านโฆษณาของเรา +

    +
    +

    วัตถุประสงค์:

    +
      +
    • แสดงโฆษณาที่เกี่ยวข้องกับความสนใจของท่าน
    • +
    • วัดประสิทธิภาพของแคมเปญโฆษณา
    • +
    • จำกัดจำนวนครั้งที่เห็นโฆษณา
    • +
    +
    +

    + คุกกี้เหล่านี้ ต้องได้รับความยินยอม จากท่านก่อนการใช้งาน เราไม่ใช้คุกกี้เพื่อการตลาดโดยตรงบนเว็บไซต์นี้ แต่หากมีการใช้งาน ท่านจะได้รับแจ้งและสามารถให้ความยินยอมหรือปฏิเสธได้ +

    + + {/* Section 7: Managing Cookies */} +

    7. การจัดการคุกกี้

    +

    + ท่านสามารถจัดการความยินยอมคุกกี้ได้หลายวิธี: +

    + +

    7.1 แบนเนอร์คุกกี้บนเว็บไซต์

    +

    + เมื่อท่านเข้าชมเว็บไซต์ครั้งแรก ท่านจะเห็นแบนเนอร์คุกกี้ที่ให้ท่านเลือก: +

    +
      +
    • ยอมรับทั้งหมด - อนุญาตคุกกี้ทุกประเภท
    • +
    • ปฏิเสธทั้งหมด - ปฏิเสธคุกกี้ที่ไม่จำเป็น
    • +
    • ตั้งค่าเอง - เลือกประเภทคุกกี้ที่ต้องการเป็นรายตัว
    • +
    + +

    7.2 การเปลี่ยนแปลงการตั้งค่า

    +

    + ท่านสามารถเปลี่ยนแปลงการตั้งค่าคุกกี้ได้ตลอดเวลา โดย: +

    +
      +
    • ล้างข้อมูลคุกกี้ในเบราว์เซอร์ของท่าน
    • +
    • เข้าชมเว็บไซต์อีกครั้งเพื่อแสดงแบนเนอร์คุกกี้ใหม่
    • +
    • ติดต่อเราเพื่อขอลบข้อมูลคุกกี้ที่เราเก็บรวบรวม
    • +
    + +

    7.3 การปิดใช้งานในเบราว์เซอร์

    +

    + ท่านสามารถปฏิเสธหรือบล็อกคุกกี้ได้โดยการเปลี่ยนแปลงการตั้งค่าในเบราว์เซอร์: +

    +
      +
    • Chrome: การตั้งค่า > ความเป็นส่วนตัวและการรักษาความปลอดภัย > คุกกี้
    • +
    • Firefox: การตั้งค่า > ความเป็นส่วนตัวและการรักษาความปลอดภัย
    • +
    • Safari: การตั้งค่า > ความเป็นส่วนตัว
    • +
    • Edge: การตั้งค่า > คุกกี้และการอนุญาตไซต์
    • +
    +

    + หมายเหตุ: การปิดใช้งานคุกกี้อาจส่งผลกระทบต่อการทำงานของเว็บไซต์บางส่วน +

    + + {/* Section 8: Policy Changes */} +

    8. การเปลี่ยนแปลงนโยบาย

    +

    + เราอาจอัปเดตนโยบายคุกกี้นี้เป็นครั้งคราวเพื่อให้สอดคล้องกับการเปลี่ยนแปลงของเว็บไซต์หรือกฎหมาย การเปลี่ยนแปลงที่สำคัญจะถูกประกาศบนหน้านี้พร้อมวันที่อัปเดตใหม่ +

    +

    + เราขอแนะนำให้ท่านตรวจสอบนโยบายนี้เป็นระยะเพื่อรับทราบการเปลี่ยนแปลง +

    + + {/* Section 9: Contact */} +

    9. การติดต่อ

    +

    + หากท่านมีคำถามเกี่ยวกับนโยบายคุกกี้นี้ กรุณาติดต่อเรา: +

    +
      +
    • อีเมล: contact@moreminimore.com
    • +
    • โทรศัพท์: 080-995-5945
    • +
    • ที่อยู่: 53 หมู่ 1 ต.บ้านแพ้ว อ.บ้านแพ้ว สมุทรสาคร 74120
    • +
    + + {/* Footer Note */} +
    +

    + หมายเหตุ: นโยบายคุกกี้นี้เป็นส่วนหนึ่งของ นโยบายความเป็นส่วนตัว และ ข้อกำหนดและเงื่อนไข ของเรา +

    +
    +
    +
    +
    +
    + ) +} diff --git a/src/app/(frontend)/faq/layout.tsx b/src/app/(frontend)/faq/layout.tsx new file mode 100644 index 0000000..e3c044b --- /dev/null +++ b/src/app/(frontend)/faq/layout.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'คำถามที่พบบ่อย | MoreminiMore - FAQ', + description: 'คำตอบสำหรับคำถามที่พบบ่อยเกี่ยวกับบริการรับทำเว็บไซต์ AI Chatbot และ Marketing Automation', + keywords: 'FAQ, คำถามที่พบบ่อย, รับทำเว็บไซต์, AI Chatbot, Marketing Automation', + openGraph: { + title: 'คำถามที่พบบ่อย | MoreminiMore - FAQ', + description: 'คำตอบสำหรับคำถามที่พบบ่อยเกี่ยวกับบริการรับทำเว็บไซต์ AI Chatbot และ Marketing Automation', + url: 'https://moreminimore.com/faq', + siteName: 'MoreminiMore', + locale: 'th_TH', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'คำถามที่พบบ่อย | MoreminiMore - FAQ', + description: 'คำตอบสำหรับคำถามที่พบบ่อยเกี่ยวกับบริการรับทำเว็บไซต์ AI Chatbot และ Marketing Automation', + }, + alternates: { + canonical: 'https://moreminimore.com/faq', + }, +} + +export default function FAQLayout({ + children, +}: { + children: React.ReactNode +}) { + return children +} diff --git a/src/app/(frontend)/faq/page.tsx b/src/app/(frontend)/faq/page.tsx new file mode 100644 index 0000000..0278cdd --- /dev/null +++ b/src/app/(frontend)/faq/page.tsx @@ -0,0 +1,200 @@ +'use client' + +import { useState } from 'react' + +interface FAQItem { + q: string + a: string +} + +interface FAQCategory { + category: string + questions: FAQItem[] +} + +const faqs: FAQCategory[] = [ + { + category: 'บริการ', + questions: [ + { + q: 'AI-Enhanced Website ต่างจากเว็บไซต์ทั่วไปอย่างไร?', + a: 'AI-Enhanced Website จะผสาน AI Chatbot ที่ตอบคำถามลูกค้าอัตโนมัติ 24/7 พร้อมระบบ SEO ที่ช่วยให้เว็บติดอันดับ Google ได้ง่ายขึ้น และมีระบบวิเคราะห์พฤติกรรมผู้ใช้งานเพื่อปรับปรุงเว็บไซต์อย่างต่อเนื่อง' + }, + { + q: 'Marketing Automation ช่วยธุรกิจฉันได้อย่างไร?', + a: 'ระบบจะช่วยให้คุณสื่อสารกับลูกค้าโดยอัตโนมัติ ผ่านหลายช่องทางเช่น LINE OA, Facebook Messenger, Email ช่วยลดงานซ้ำซ้อน เพิ่มการตอบสนองที่รวดเร็ว และติดตามผลการตลาดได้อย่างแม่นยำ' + }, + { + q: 'SEO + AI Content System ทำงานอย่างไร?', + a: 'เราใช้ AI วิจัย Keyword ที่มีศักยภาพ สร้างคอนเทนต์คุณภาพที่ตรงใจกลุ่มเป้าหมาย และปรับแต่งให้ถูกใจ Google ช่วยให้เว็บติดอันดับการค้นหาอย่างยั่งยืน' + }, + { + q: 'Tech Consult จำเป็นสำหรับธุรกิจฉันไหม?', + a: 'หากคุณกำลังวางแผนใช้เทคโนโลยีใหม่ ขยายระบบ หรือต้องการเลือกเครื่องมือที่เหมาะสมกับธุรกิจ การปรึกษาก่อนเริ่มโครงการจะช่วยประหยัดเวลาและงบประมาณได้มาก' + } + ] + }, + { + category: 'กระบวนการทำงาน', + questions: [ + { + q: 'เริ่มต้นใช้บริการอย่างไร?', + a: 'ติดต่อเราเพื่อคุยกันและให้คำปรึกษาฟรี! เราจะพูดคุยความต้องการ ธุรกิจ และเป้าหมายของคุณ จากนั้นจึงแนะนำโซลูชันที่เหมาะสมที่สุด' + }, + { + q: 'ใช้เวลานานแค่ไหนถึงจะเห็นผล?', + a: 'ขึ้นอยู่กับบริการ: เว็บไซต์ใช้เวลา 2-6 สัปดาห์, Marketing Automation เห็นผลใน 1-3 เดือน, SEO ใช้เวลา 3-6 เดือนในการติดอันดับ' + }, + { + q: 'มีบริการหลังการขายไหม?', + a: 'มี! เราดูแลหลังการติดตั้ง อบรมการใช้งาน และพร้อมให้คำปรึกษาเมื่อคุณต้องการ' + }, + { + q: 'ต้องมีความรู้ทางเทคนิคไหม?', + a: 'ไม่จำเป็น! เราดูแลทุกอย่างตั้งแต่ต้นจนจบ และอบรมทีมของคุณให้ใช้งานระบบได้อย่างมั่นใจ' + } + ] + }, + { + category: 'ราคาและการชำระเงิน', + questions: [ + { + q: 'มี Package ไหนบ้าง?', + a: 'เรามีหลาย Package ตั้งแต่เริ่มต้นหลักพัน ไปจนถึงโครงการใหญ่ ขึ้นอยู่กับความต้องการและขอบเขตงาน นอกจากนี้ยังมีบริการที่คิดเป็นรายเดือน (ที่ปรึกษา) ที่จะช่วยพัฒนาระบบได้เรื่อย ๆ ไม่จำกัดด้วย โดยราคาจะขึ้นอยู่กับขอบเขตและความยากของงาน เหมาะสำหรับลูกค้าที่มีความต้องการเปลี่ยนแปลงตลอดเวลา' + }, + { + q: 'มีบริการแบบรายเดือนไหม?', + a: 'มี! บริการบางอย่างเช่น SEO, Marketing Automation มีแบบรายเดือน ซึ่งรวมถึงการดูแลอย่างต่อเนื่องและปรับปรุงระบบ' + }, + { + q: 'ชำระเงินได้อย่างไร?', + a: 'รับชำระเงินผ่านการโอนเงินธนาคาร บริษัทออกใบเสร็จและใบกำกับภาษีให้ได้' + } + ] + }, + { + category: 'เทคนิคและการรองรับ', + questions: [ + { + q: 'เว็บไซต์รองรับมือถือไหม?', + a: 'รองรับ 100%! ทุกเว็บไซต์ที่เราทำเป็น Responsive Design แสดงผลสวยงามทั้งบนมือถือ แท็บเล็ต และคอมพิวเตอร์' + }, + { + q: 'มี Warranty ไหม?', + a: 'มี! เราให้ Warranty สำหรับ bug และ error ที่เกิดจากระบบของเรา ตลอดอายุสัญญา' + }, + { + q: 'ถ้ามีปัญหาต้องทำอย่างไร?', + a: 'ติดต่อเราได้หลายช่องทาง: โทรศัพท์, LINE, Email เราจะตอบกลับภายใน 24 ชั่วโมงทำการ' + } + ] + } +] + +export default function FAQPage() { + const [openItems, setOpenItems] = useState>({}) + + const toggleItem = (category: string, index: number) => { + const key = `${category}-${index}` + setOpenItems(prev => ({ + ...prev, + [key]: !prev[key] + })) + } + + return ( +
    + {/* Hero Section */} +
    + {/* Floating Shapes */} +
    +
    +
    + + {/* Grid Pattern */} +
    + +
    +
    +

    + คำถามที่พบบ่อย +

    +

    + รวบรวมคำถามที่ลูกค้าถามบ่อย พร้อมคำตอบที่ชัดเจน +

    +
    +
    +
    + + {/* FAQ Content */} +
    +
    + {faqs.map((category) => ( +
    +

    + + {category.category} +

    +
    + {category.questions.map((faq, index) => { + const key = `${category.category}-${index}` + const isOpen = openItems[key] + return ( +
    + + {isOpen && ( +
    + {faq.a} +
    + )} +
    + ) + })} +
    +
    + ))} + + {/* CTA Section */} +
    +

    + ยังมีคำถามอื่นอีก? +

    +

    + ติดต่อเรามาได้เลย ยินดีให้คำปรึกษาฟรี! +

    + +
    +
    +
    +
    + ) +} diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css new file mode 100644 index 0000000..740ff0b --- /dev/null +++ b/src/app/(frontend)/globals.css @@ -0,0 +1,130 @@ +@import "tailwindcss"; + +@theme { + --color-primary: #fed400; + --color-primary-hover: #e6c200; + --color-dark: #111827; + --color-dark-secondary: #1f2937; + --color-gray-50: #f9fafb; + --color-gray-100: #f3f4f6; + --color-gray-200: #e5e7eb; + --color-gray-300: #d1d5db; + --color-gray-400: #9ca3af; + --color-gray-500: #6b7280; + --color-gray-600: #4b5563; + --color-gray-700: #374151; + --color-gray-800: #1f2937; + --color-gray-900: #111827; + --color-white: #ffffff; + --color-accent-blue: #0ea5e9; + --color-accent-teal: #0d9488; + --color-accent-purple: #7c3aed; + --color-accent-green: #16a34a; + + --font-kanit: 'Kanit', sans-serif; + --font-noto: 'Noto Sans Thai', sans-serif; +} + +@layer base { + html { + scroll-behavior: smooth; + } + + body { + font-family: var(--font-noto), system-ui, sans-serif; + color: var(--color-dark); + background-color: var(--color-white); + line-height: 1.7; + } + + h1, h2, h3, h4, h5, h6 { + font-family: var(--font-kanit), system-ui, sans-serif; + font-weight: 700; + line-height: 1.2; + } + + a { + color: inherit; + text-decoration: none; + } + + a:hover { + text-decoration: none; + } +} + +/* Reveal animations */ +.reveal { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.reveal.visible { + opacity: 1; + transform: translateY(0); +} + +.reveal-left { + opacity: 0; + transform: translateX(-30px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.reveal-left.visible { + opacity: 1; + transform: translateX(0); +} + +.reveal-right { + opacity: 0; + transform: translateX(30px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.reveal-right.visible { + opacity: 1; + transform: translateX(0); +} + +/* Float animations */ +@keyframes float { + 0%, 100% { transform: translateY(0px); } + 50% { transform: translateY(-20px); } +} + +@keyframes floatDot { + 0%, 100% { transform: translateY(0px) scale(1); } + 50% { transform: translateY(-10px) scale(1.2); } +} + +.animate-float-1 { animation: float 6s ease-in-out infinite; } +.animate-float-2 { animation: float 8s ease-in-out infinite 2s; } +.animate-float-3 { animation: float 7s ease-in-out infinite 4s; } +.animate-float-dot-1 { animation: floatDot 4s ease-in-out infinite; } +.animate-float-dot-2 { animation: floatDot 5s ease-in-out infinite 1s; } +.animate-float-dot-3 { animation: floatDot 6s ease-in-out infinite 2s; } + +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +.animate-fade-in-up { + animation: fadeInUp 0.8s ease forwards; +} + +/* Line clamp utilities */ +.line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.line-clamp-3 { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} diff --git a/src/app/(frontend)/layout.tsx b/src/app/(frontend)/layout.tsx new file mode 100644 index 0000000..2feebe0 --- /dev/null +++ b/src/app/(frontend)/layout.tsx @@ -0,0 +1,82 @@ +import type { Metadata } from 'next' +import './globals.css' +import Navigation from '@/components/Navigation' +import Footer from '@/components/Footer' +import CookieBanner from '@/components/CookieBanner' +import { getPayload } from 'payload' +import config from '@payload-config' + +export const metadata: Metadata = { + metadataBase: new URL(process.env.NEXT_PUBLIC_SERVER_URL || 'https://moreminimore.com'), + title: { + default: 'MoreminiMore - ที่ปรึกษาองค์กร AI เพิ่มยอดขายด้วยข้อมูล', + template: '%s | MoreminiMore', + }, + description: 'เราให้คำปรึกษาด้าน AI Transformation กลยุทธ์การตลาดโดยใช้ข้อมูลเป็นพื้นฐาน พัฒนาศักยภาพของบุคลากรให้สูงขึ้น เพื่อเพิ่มยอดขายให้กับลูกค้าให้มากที่สุด', + keywords: ['AI', 'AI Transformation', 'Marketing Automation', 'Web Development', 'Chatbot', 'Thai SME'], + authors: [{ name: 'MoreminiMore Co., Ltd.' }], + creator: 'MoreminiMore Co., Ltd.', + publisher: 'MoreminiMore Co., Ltd.', + formatDetection: { + email: false, + address: false, + telephone: false, + }, + openGraph: { + type: 'website', + locale: 'th_TH', + url: 'https://moreminimore.com', + siteName: 'MoreminiMore', + title: 'MoreminiMore - ที่ปรึกษาองค์กร AI เพิ่มยอดขายด้วยข้อมูล', + description: 'เราให้คำปรึกษาด้าน AI Transformation กลยุทธ์การตลาดโดยใช้ข้อมูลเป็นพื้นฐาน', + images: [{ url: '/branding/logo-long.png', width: 200, height: 50, alt: 'MoreminiMore' }], + }, + twitter: { + card: 'summary_large_image', + title: 'MoreminiMore - ที่ปรึกษาองค์กร AI เพิ่มยอดขายด้วยข้อมูล', + description: 'เราให้คำปรึกษาด้าน AI Transformation กลยุทธ์การตลาดโดยใช้ข้อมูลเป็นพื้นฐาน', + images: ['/branding/logo-long.png'], + }, + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + 'max-video-preview': -1, + 'max-image-preview': 'large', + 'max-snippet': -1, + }, + }, + verification: { + google: 'your-google-verification-code', + }, +} + +export default async function FrontendLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + + + + + + + + + +
    {children}
    +