feat(audit): implement page view logging for membership confirmation and analysis results
This commit is contained in:
@@ -5,6 +5,10 @@ import pathsConfig from '@/config/paths.config';
|
|||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
|
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||||
|
import {
|
||||||
|
PAGE_VIEW_ACTION,
|
||||||
|
createPageViewLog,
|
||||||
|
} from '~/lib/services/audit/pageView.service';
|
||||||
|
|
||||||
import MembershipConfirmationNotification from './_components/membership-confirmation-notification';
|
import MembershipConfirmationNotification from './_components/membership-confirmation-notification';
|
||||||
|
|
||||||
@@ -18,6 +22,10 @@ async function MembershipConfirmation() {
|
|||||||
if (!user?.id) {
|
if (!user?.id) {
|
||||||
redirect(pathsConfig.app.home);
|
redirect(pathsConfig.app.home);
|
||||||
}
|
}
|
||||||
|
await createPageViewLog({
|
||||||
|
accountId: user.id,
|
||||||
|
action: PAGE_VIEW_ACTION.REGISTRATION_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
return <MembershipConfirmationNotification userId={user.id} />;
|
return <MembershipConfirmationNotification userId={user.id} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { redirect } from 'next/navigation';
|
||||||
|
|
||||||
|
import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account';
|
||||||
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
import { createI18nServerInstance } from '@/lib/i18n/i18n.server';
|
||||||
import { withI18n } from '@/lib/i18n/with-i18n';
|
import { withI18n } from '@/lib/i18n/with-i18n';
|
||||||
|
|
||||||
@@ -7,14 +9,16 @@ import { Trans } from '@kit/ui/makerkit/trans';
|
|||||||
import { PageBody } from '@kit/ui/page';
|
import { PageBody } from '@kit/ui/page';
|
||||||
import { Button } from '@kit/ui/shadcn/button';
|
import { Button } from '@kit/ui/shadcn/button';
|
||||||
|
|
||||||
|
import pathsConfig from '~/config/paths.config';
|
||||||
|
import { getAnalysisElements } from '~/lib/services/analysis-element.service';
|
||||||
|
import {
|
||||||
|
PAGE_VIEW_ACTION,
|
||||||
|
createPageViewLog,
|
||||||
|
} from '~/lib/services/audit/pageView.service';
|
||||||
|
import { getAnalysisOrders } from '~/lib/services/order.service';
|
||||||
|
|
||||||
import { loadUserAnalysis } from '../../_lib/server/load-user-analysis';
|
import { loadUserAnalysis } from '../../_lib/server/load-user-analysis';
|
||||||
import Analysis from './_components/analysis';
|
import Analysis from './_components/analysis';
|
||||||
import pathsConfig from '~/config/paths.config';
|
|
||||||
import { redirect } from 'next/navigation';
|
|
||||||
import { getAnalysisOrders } from '~/lib/services/order.service';
|
|
||||||
import { getAnalysisElements } from '~/lib/services/analysis-element.service';
|
|
||||||
import { loadCurrentUserAccount } from '@/app/home/(user)/_lib/server/load-user-account';
|
|
||||||
import { createPageViewLog } from '~/lib/services/audit/pageView.service';
|
|
||||||
|
|
||||||
export const generateMetadata = async () => {
|
export const generateMetadata = async () => {
|
||||||
const i18n = await createI18nServerInstance();
|
const i18n = await createI18nServerInstance();
|
||||||
@@ -26,13 +30,15 @@ export const generateMetadata = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function AnalysisResultsPage() {
|
async function AnalysisResultsPage() {
|
||||||
const account = await loadCurrentUserAccount()
|
const account = await loadCurrentUserAccount();
|
||||||
if (!account) {
|
if (!account) {
|
||||||
throw new Error('Account not found');
|
throw new Error('Account not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const analysisResponses = await loadUserAnalysis();
|
const analysisResponses = await loadUserAnalysis();
|
||||||
const analysisResponseElements = analysisResponses?.flatMap(({ elements }) => elements);
|
const analysisResponseElements = analysisResponses?.flatMap(
|
||||||
|
({ elements }) => elements,
|
||||||
|
);
|
||||||
|
|
||||||
const analysisOrders = await getAnalysisOrders().catch(() => null);
|
const analysisOrders = await getAnalysisOrders().catch(() => null);
|
||||||
|
|
||||||
@@ -42,29 +48,46 @@ async function AnalysisResultsPage() {
|
|||||||
|
|
||||||
await createPageViewLog({
|
await createPageViewLog({
|
||||||
accountId: account.id,
|
accountId: account.id,
|
||||||
action: 'VIEW_ANALYSIS_RESULTS',
|
action: PAGE_VIEW_ACTION.VIEW_ANALYSIS_RESULTS,
|
||||||
});
|
});
|
||||||
|
|
||||||
const analysisElementIds = [
|
const analysisElementIds = [
|
||||||
...new Set(analysisOrders?.flatMap((order) => order.analysis_element_ids).filter(Boolean) as number[]),
|
...new Set(
|
||||||
|
analysisOrders
|
||||||
|
?.flatMap((order) => order.analysis_element_ids)
|
||||||
|
.filter(Boolean) as number[],
|
||||||
|
),
|
||||||
];
|
];
|
||||||
const analysisElements = await getAnalysisElements({ ids: analysisElementIds });
|
const analysisElements = await getAnalysisElements({
|
||||||
const analysisElementsWithResults = analysisResponseElements
|
ids: analysisElementIds,
|
||||||
|
});
|
||||||
|
const analysisElementsWithResults =
|
||||||
|
analysisResponseElements
|
||||||
?.sort((a, b) => {
|
?.sort((a, b) => {
|
||||||
if (!a.response_time || !b.response_time) {
|
if (!a.response_time || !b.response_time) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return new Date(b.response_time).getTime() - new Date(a.response_time).getTime();
|
return (
|
||||||
|
new Date(b.response_time).getTime() -
|
||||||
|
new Date(a.response_time).getTime()
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.map((results) => ({ results })) ?? [];
|
.map((results) => ({ results })) ?? [];
|
||||||
const analysisElementsWithoutResults = analysisElements
|
const analysisElementsWithoutResults = analysisElements.filter(
|
||||||
.filter((element) => !analysisElementsWithResults?.some(({ results }) => results.analysis_element_original_id === element.analysis_id_original));
|
(element) =>
|
||||||
|
!analysisElementsWithResults?.some(
|
||||||
|
({ results }) =>
|
||||||
|
results.analysis_element_original_id === element.analysis_id_original,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
const hasNoAnalysisElements = analysisElementsWithResults.length === 0 && analysisElementsWithoutResults.length === 0;
|
const hasNoAnalysisElements =
|
||||||
|
analysisElementsWithResults.length === 0 &&
|
||||||
|
analysisElementsWithoutResults.length === 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<div className="mt-8 flex flex-col sm:flex-row sm:items-center justify-between gap-4 sm:gap-0">
|
<div className="mt-8 flex flex-col justify-between gap-4 sm:flex-row sm:items-center sm:gap-0">
|
||||||
<div>
|
<div>
|
||||||
<h4>
|
<h4>
|
||||||
<Trans i18nKey="analysis-results:pageTitle" />
|
<Trans i18nKey="analysis-results:pageTitle" />
|
||||||
@@ -85,16 +108,27 @@ async function AnalysisResultsPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{analysisElementsWithResults.map(({ results }) => {
|
{analysisElementsWithResults.map(({ results }) => {
|
||||||
const analysisElement = analysisElements.find((element) => element.analysis_id_original === results.analysis_element_original_id);
|
const analysisElement = analysisElements.find(
|
||||||
|
(element) =>
|
||||||
|
element.analysis_id_original ===
|
||||||
|
results.analysis_element_original_id,
|
||||||
|
);
|
||||||
if (!analysisElement) {
|
if (!analysisElement) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Analysis key={results.id} analysisElement={analysisElement} results={results} />
|
<Analysis
|
||||||
|
key={results.id}
|
||||||
|
analysisElement={analysisElement}
|
||||||
|
results={results}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{analysisElementsWithoutResults.map((element) => (
|
{analysisElementsWithoutResults.map((element) => (
|
||||||
<Analysis key={element.analysis_id_original} analysisElement={element} />
|
<Analysis
|
||||||
|
key={element.analysis_id_original}
|
||||||
|
analysisElement={element}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
{hasNoAnalysisElements && (
|
{hasNoAnalysisElements && (
|
||||||
<div className="text-muted-foreground text-sm">
|
<div className="text-muted-foreground text-sm">
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
|
|
||||||
|
export enum PAGE_VIEW_ACTION {
|
||||||
|
VIEW_ANALYSIS_RESULTS = 'VIEW_ANALYSIS_RESULTS',
|
||||||
|
REGISTRATION_SUCCESS = 'REGISTRATION_SUCCESS',
|
||||||
|
}
|
||||||
|
|
||||||
export const createPageViewLog = async ({
|
export const createPageViewLog = async ({
|
||||||
accountId,
|
accountId,
|
||||||
action,
|
action,
|
||||||
}: {
|
}: {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
action: 'VIEW_ANALYSIS_RESULTS';
|
action: PAGE_VIEW_ACTION;
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
const supabase = getSupabaseServerClient();
|
const supabase = getSupabaseServerClient();
|
||||||
@@ -32,4 +37,4 @@ export const createPageViewLog = async ({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to insert page view log', error);
|
console.error('Failed to insert page view log', error);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user