diff --git a/next/next.config.ts b/next/next.config.ts index 3fb69046..6c0434e4 100644 --- a/next/next.config.ts +++ b/next/next.config.ts @@ -8,6 +8,11 @@ const analyzeBundles = withBundleAnalyzer({ }); /** @type {import('next').NextConfig} */ const config: NextConfig = { + logging: { + fetches: { + fullUrl: true, + }, + }, experimental: { serverActions: { bodySizeLimit: "5mb", diff --git a/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-management-tab.tsx b/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-management-tab.tsx index 9d33853f..18615746 100644 --- a/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-management-tab.tsx +++ b/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-management-tab.tsx @@ -34,9 +34,6 @@ export function PageManagementTab({ shallow: false, }), ); - const handlePageChange = (newPage: number) => { - setPage(newPage); - }; const getStatusBadge = (status: PageStatus) => { if (status === "PUBLIC") { @@ -100,7 +97,7 @@ export function PageManagementTab({ diff --git a/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-view-data/view-data.ts b/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-view-data/view-data.ts index 796ae6bc..cb08373c 100644 --- a/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-view-data/view-data.ts +++ b/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/components/page-view-data/view-data.ts @@ -1,5 +1,5 @@ import { BetaAnalyticsDataClient } from "@google-analytics/data"; - +import { unstable_cache } from "next/cache"; export interface GeoViewData { country: string; views: number; @@ -24,52 +24,59 @@ function getCredentialsFromBase64() { } // Google Analytics データ取得関数 -export async function getGeoViewData(path: string): Promise { - try { - // サービスアカウント認証と Analytics Data クライアントの初期化 - const analyticsDataClient = new BetaAnalyticsDataClient({ - credentials: getCredentialsFromBase64(), - }); +export const getGeoViewData = unstable_cache( + async (path: string) => { + try { + // サービスアカウント認証と Analytics Data クライアントの初期化 + const analyticsDataClient = new BetaAnalyticsDataClient({ + credentials: getCredentialsFromBase64(), + }); - // 地域別ページビューデータを取得 - const propertyId = process.env.GOOGLE_ANALYTICS_PROPERTY_ID; + // 地域別ページビューデータを取得 + const propertyId = process.env.GOOGLE_ANALYTICS_PROPERTY_ID; - if (!propertyId) { - throw new Error("GA4_PROPERTY_ID is not defined"); - } + if (!propertyId) { + throw new Error("GA4_PROPERTY_ID is not defined"); + } - const [response] = await analyticsDataClient.runReport({ - property: `properties/${propertyId}`, - dateRanges: [{ startDate: "420daysAgo", endDate: "today" }], - dimensions: [{ name: "country" }], - metrics: [{ name: "screenPageViews" }], - dimensionFilter: { - filter: { - fieldName: "pagePath", - stringFilter: { - matchType: "CONTAINS", - value: path, + const [response] = await analyticsDataClient.runReport({ + property: `properties/${propertyId}`, + dateRanges: [{ startDate: "420daysAgo", endDate: "today" }], + dimensions: [{ name: "country" }], + metrics: [{ name: "screenPageViews" }], + dimensionFilter: { + filter: { + fieldName: "pagePath", + stringFilter: { + matchType: "CONTAINS", + value: path, + }, }, }, - }, - orderBys: [ - { - metric: { metricName: "screenPageViews" }, - desc: true, - }, - ], - limit: 10, - }); + orderBys: [ + { + metric: { metricName: "screenPageViews" }, + desc: true, + }, + ], + limit: 10, + }); - // データを整形 - return ( - response.rows?.map((row) => ({ - country: row.dimensionValues?.[0].value || "", - views: Number(row.metricValues?.[0].value || "0"), - })) || [] - ); - } catch (error) { - console.error("Analytics API error:", error); - return []; - } -} + // データを整形 + return ( + response.rows?.map((row) => ({ + country: row.dimensionValues?.[0].value || "", + views: Number(row.metricValues?.[0].value || "0"), + })) || [] + ); + } catch (error) { + console.error("Analytics API error:", error); + return []; + } + }, + [], + { + revalidate: 3600, // 1時間でキャッシュを再検証 + tags: ["analytics-data"], + }, +); diff --git a/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/page.tsx b/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/page.tsx index 2dd2d502..b1e15512 100644 --- a/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/page.tsx +++ b/next/src/app/[locale]/(common-layout)/user/[handle]/page-management/page.tsx @@ -1,4 +1,5 @@ -import { auth } from "@/auth"; +import { getCurrentUser } from "@/auth"; +import { redirect } from "next/navigation"; import { PageManagementTab } from "./components/page-management-tab"; import { getGeoViewData } from "./components/page-view-data/view-data"; import { fetchPaginatedOwnPages } from "./db/queries.server"; @@ -9,10 +10,9 @@ export default async function PageManagementPage({ params: Promise<{ locale: string }>; searchParams: Promise<{ [key: string]: string | string[] | undefined }>; }) { - const session = await auth(); - const currentUser = session?.user; + const currentUser = await getCurrentUser(); if (!currentUser || !currentUser.id) { - throw new Error("Unauthorized"); + return redirect("/auth/login"); } const { locale } = await params; const { page = "1", query = "" } = await searchParams; diff --git a/next/src/app/[locale]/(edit-layout)/user/[handle]/page/[slug]/edit/components/header/index.tsx b/next/src/app/[locale]/(edit-layout)/user/[handle]/page/[slug]/edit/components/header/index.tsx index 98b79c69..aebcd010 100644 --- a/next/src/app/[locale]/(edit-layout)/user/[handle]/page/[slug]/edit/components/header/index.tsx +++ b/next/src/app/[locale]/(edit-layout)/user/[handle]/page/[slug]/edit/components/header/index.tsx @@ -11,7 +11,6 @@ import { Separator } from "@/components/ui/separator"; import { Link } from "@/i18n/routing"; import type { PageStatus } from "@prisma/client"; import { - ArrowRight, Check, Globe, InfoIcon, @@ -113,8 +112,8 @@ export function EditHeader({ {initialStatus === "PUBLIC" ? "Public" : "Private"} - -
+ +
- Public - Translates to:
-
+
EN
JP
diff --git a/next/src/app/[locale]/components/hero-section/index.tsx b/next/src/app/[locale]/components/hero-section/index.tsx index 2c23881c..919f98b0 100644 --- a/next/src/app/[locale]/components/hero-section/index.tsx +++ b/next/src/app/[locale]/components/hero-section/index.tsx @@ -7,6 +7,8 @@ import { TranslateActionSection } from "@/app/[locale]/components/translate-acti import { fetchPageWithTranslations } from "@/app/[locale]/db/queries.server"; import { fetchLatestPageAITranslationInfo } from "@/app/[locale]/db/queries.server"; import { notFound } from "next/navigation"; + +export const revalidate = 3600; export default async function HeroSection({ locale }: { locale: string }) { const pageSlug = locale === "ja" ? "evame" : "evame-ja"; const topPageWithTranslations = await fetchPageWithTranslations( diff --git a/next/src/app/api/og/route.tsx b/next/src/app/api/og/route.tsx index 02496b4a..194981ca 100644 --- a/next/src/app/api/og/route.tsx +++ b/next/src/app/api/og/route.tsx @@ -3,6 +3,7 @@ import { join } from "node:path"; import { fetchPageContext } from "@/app/[locale]/(common-layout)/user/[handle]/page/[slug]/page"; import { ImageResponse } from "next/og"; +export const revalidate = 3600; export async function GET(req: Request): Promise { const { searchParams } = new URL(req.url); const interFontSemiBold = await readFile(