feat: add update log tab

This commit is contained in:
Sosokker 2024-11-10 23:01:50 +07:00
parent 121c609077
commit c7766f78fc
5 changed files with 160 additions and 9 deletions

View File

@ -0,0 +1,72 @@
import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
import { getProjectLogByProjectId } from "@/lib/data/projectLogQuery";
import { LogEntry, parseProjectLog } from "./logParser";
import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card";
export const UpdateTab = async ({ projectId }: { projectId: number }) => {
const supabase = createSupabaseClient();
const { data, error } = await getProjectLogByProjectId(supabase, projectId);
if (error) {
return (
<div className="flex justify-center items-center h-full">
<Card>
<CardContent>
<div className="text-center text-gray-500">
<CardTitle className="mb-3 mt-4">No updates available</CardTitle>
<CardDescription>There are no updates to display at this time. Please check back later.</CardDescription>
</div>
</CardContent>
</Card>
</div>
);
}
const parsedLogs = parseProjectLog(data as unknown as LogEntry[]);
if (parsedLogs.length === 0) {
return (
<div className="flex justify-center items-center h-full">
<Card>
<CardContent>
<div className="text-center text-gray-500">
<CardTitle className="mb-3 mt-4">No updates available</CardTitle>
<CardDescription>There are no updates to display at this time. Please check back later.</CardDescription>
</div>
</CardContent>
</Card>
</div>
);
}
return (
<div className="w-full">
{parsedLogs.map((log, index) => (
<div key={index} className="grid grid-cols-3 gap-4 overflow-y-auto">
<Card>
<CardHeader>
<CardTitle>{log.table}</CardTitle>
<CardDescription>{log.changes.length} Changes</CardDescription>
</CardHeader>
<CardContent className="grid grid-cols-2 overflow-y-auto h-1/2 mx-4">
{log.changes.map((change, changeIndex) => (
<div key={changeIndex} className="mb-3">
<div className="text-sm font-semibold">{change.field}</div>
<div className="text-gray-500">
<span className="text-red-500">From:</span> {JSON.stringify(change.from)}
</div>
<div className="text-gray-500">
<span className="text-green-500">To:</span> {JSON.stringify(change.to)}
</div>
</div>
))}
</CardContent>
<CardFooter>
<div className="text-xs text-gray-500">Updated at: {new Date(log.changed_at).toLocaleString()}</div>
</CardFooter>
</Card>
</div>
))}
</div>
);
};

View File

@ -0,0 +1,57 @@
export interface LogEntry {
id: number;
operation_type: string;
record_id: number;
old_data: Record<string, any>;
new_data: Record<string, any>;
changed_at: string;
table_name: string;
}
type ChangeSummary = {
field: string;
from: any;
to: any;
};
function parseProjectLog(logs: LogEntry[]): { changes: ChangeSummary[]; table: string; changed_at: string }[] {
return logs.map((log) => {
const changes: ChangeSummary[] = [];
if (log.table_name === "project_investment_detail") {
if (log.operation_type === "UPDATE") {
for (const key in log.old_data) {
if (log.old_data[key] !== log.new_data[key]) {
changes.push({
field: key,
from: log.old_data[key],
to: log.new_data[key],
});
}
}
}
}
if (log.table_name === "project") {
if (log.operation_type === "UPDATE") {
for (const key in log.old_data) {
if (log.old_data[key] !== log.new_data[key]) {
changes.push({
field: key,
from: log.old_data[key],
to: log.new_data[key],
});
}
}
}
}
return {
table: log.table_name,
changed_at: log.changed_at,
changes,
};
});
}
export { parseProjectLog };

View File

@ -17,6 +17,7 @@ import { getDealList } from "@/app/api/dealApi";
import { sumByKey, toPercentage } from "@/lib/utils"; import { sumByKey, toPercentage } from "@/lib/utils";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { isOwnerOfProject } from "./query"; import { isOwnerOfProject } from "./query";
import { UpdateTab } from "./UpdateTab";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
const PHOTO_MATERIAL_ID = 2; const PHOTO_MATERIAL_ID = 2;
@ -241,11 +242,11 @@ export default async function ProjectDealPage({ params }: { params: { id: number
</div> </div>
{/* menu */} {/* menu */}
<div id="deck"> <div id="deck">
<div className="flex w-fit"> <div className="flex w-full">
<Tabs.Root defaultValue="pitch"> <Tabs.Root defaultValue="pitch" className="w-full">
<Tabs.List className="list-none flex gap-10 text-lg md:text-xl"> <Tabs.List className="list-none flex gap-10 text-lg md:text-xl">
<Tabs.Trigger value="pitch">Pitch</Tabs.Trigger> <Tabs.Trigger value="pitch">Pitch</Tabs.Trigger>
<Tabs.Trigger value="general">General Data</Tabs.Trigger> {/* <Tabs.Trigger value="general">General Data</Tabs.Trigger> */}
<Tabs.Trigger value="update">Updates</Tabs.Trigger> <Tabs.Trigger value="update">Updates</Tabs.Trigger>
</Tabs.List> </Tabs.List>
<Separator className="mb-4 mt-2 w-full border-1" /> <Separator className="mb-4 mt-2 w-full border-1" />
@ -253,7 +254,8 @@ export default async function ProjectDealPage({ params }: { params: { id: number
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>{projectData.project_name}</CardTitle> <CardTitle>{projectData.project_name}</CardTitle>
<CardDescription /> <CardDescription>Project Pitch</CardDescription>
<Separator className="my-4" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="prose dark:prose-invert prose-sm max-w-none "> <div className="prose dark:prose-invert prose-sm max-w-none ">
@ -264,7 +266,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number
</CardContent> </CardContent>
</Card> </Card>
</Tabs.Content> </Tabs.Content>
<Tabs.Content value="general"> {/* <Tabs.Content value="general">
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>general</CardTitle> <CardTitle>general</CardTitle>
@ -274,15 +276,16 @@ export default async function ProjectDealPage({ params }: { params: { id: number
<p>general Content</p> <p>general Content</p>
</CardContent> </CardContent>
</Card> </Card>
</Tabs.Content> </Tabs.Content> */}
<Tabs.Content value="update"> <Tabs.Content value="update">
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>update</CardTitle> <CardTitle>Update</CardTitle>
<CardDescription>update Description</CardDescription> <CardDescription>Project log and updates</CardDescription>
<Separator className="my-4" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<p>update Content</p> <UpdateTab projectId={params.id} />
</CardContent> </CardContent>
</Card> </Card>
</Tabs.Content> </Tabs.Content>

View File

@ -0,0 +1,19 @@
import { SupabaseClient } from "@supabase/supabase-js";
import { Database } from "@/types/database.types";
export function getProjectLogByProjectId(client: SupabaseClient<Database>, projectId: number) {
return client
.from("project_log")
.select(
`
id,
operation_type,
record_id,
old_data,
new_data,
changed_at,
table_name
`
)
.eq("record_id", projectId);
}

Binary file not shown.