Skip to content

Commit

Permalink
ページ管理機能の認証処理を改善し、ユーザーが未認証の場合にリダイレクトを追加しました。また、ログ取得設定を追加し、HeroSectionと…
Browse files Browse the repository at this point in the history
…OGルートの再検証時間を設定しました。EditHeaderコンポーネントのスタイルを調整しました。 (#638)
  • Loading branch information
ttizze authored Feb 27, 2025
2 parents 95f2633 + 586ab63 commit 21df552
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 60 deletions.
5 changes: 5 additions & 0 deletions next/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ const analyzeBundles = withBundleAnalyzer({
});
/** @type {import('next').NextConfig} */
const config: NextConfig = {
logging: {
fetches: {
fullUrl: true,
},
},
experimental: {
serverActions: {
bodySizeLimit: "5mb",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ export function PageManagementTab({
shallow: false,
}),
);
const handlePageChange = (newPage: number) => {
setPage(newPage);
};

const getStatusBadge = (status: PageStatus) => {
if (status === "PUBLIC") {
Expand Down Expand Up @@ -100,7 +97,7 @@ export function PageManagementTab({
<PaginationBar
totalPages={totalPages}
currentPage={currentPage}
onPageChange={handlePageChange}
onPageChange={setPage}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BetaAnalyticsDataClient } from "@google-analytics/data";

import { unstable_cache } from "next/cache";
export interface GeoViewData {
country: string;
views: number;
Expand All @@ -24,52 +24,59 @@ function getCredentialsFromBase64() {
}

// Google Analytics データ取得関数
export async function getGeoViewData(path: string): Promise<GeoViewData[]> {
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"],
},
);
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -113,8 +112,8 @@ export function EditHeader({
<span>{initialStatus === "PUBLIC" ? "Public" : "Private"}</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-34 rounded-xl p-1" align="end">
<div className="space-y-1 p-1">
<PopoverContent className="w-38 rounded-xl py-1 px-3" align="end">
<div className="space-y-1">
<form action={action}>
<input
type="hidden"
Expand All @@ -136,9 +135,9 @@ export function EditHeader({
<PopoverTrigger asChild>
<button
type="button"
className="text-xs text-muted-foreground hover:text-foreground flex items-center"
className="ml-3 text-muted-foreground hover:text-foreground flex items-center"
>
<InfoIcon className="h-3.5 w-3.5" />
<InfoIcon className="h-4 w-4" />
</button>
</PopoverTrigger>
<PopoverContent
Expand All @@ -151,12 +150,10 @@ export function EditHeader({
</div>

<div className="flex items-center justify-center gap-2 text-xs text-muted-foreground">
<span>Public</span>
<ArrowRight className="h-3.5 w-3.5 text-muted-foreground" />
<span>Translates to:</span>
</div>

<div className="bg-secondary/40 rounded-lg p-2">
<div className="bg-secondary/80 rounded-lg p-2">
<div className="grid grid-cols-4 gap-2 text-center">
<div className="text-xs font-medium">EN</div>
<div className="text-xs font-medium">JP</div>
Expand Down
2 changes: 2 additions & 0 deletions next/src/app/[locale]/components/hero-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions next/src/app/api/og/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Response> {
const { searchParams } = new URL(req.url);
const interFontSemiBold = await readFile(
Expand Down

0 comments on commit 21df552

Please sign in to comment.