<!-- .github/pull_request_template.md --> ## Description <!-- Provide a clear description of the changes in this PR --> ## DCO Affirmation I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin. --------- Co-authored-by: Igor Ilic <igorilic03@gmail.com>
54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback, useImperativeHandle, useState } from "react";
|
|
|
|
type ActivityLog = {
|
|
id: string;
|
|
timestamp: number;
|
|
activity: string;
|
|
};
|
|
|
|
export interface ActivityLogAPI {
|
|
updateActivityLog: (activityLog: ActivityLog[]) => void;
|
|
}
|
|
|
|
interface ActivityLogProps {
|
|
ref: React.RefObject<ActivityLogAPI>;
|
|
}
|
|
|
|
const formatter = new Intl.DateTimeFormat("en-GB", { dateStyle: "short", timeStyle: "medium" });
|
|
|
|
export default function ActivityLog({ ref }: ActivityLogProps) {
|
|
const [activityLog, updateActivityLog] = useState<ActivityLog[]>([]);
|
|
|
|
const handleActivityLogUpdate = useCallback(
|
|
(newActivities: ActivityLog[]) => {
|
|
updateActivityLog([...activityLog, ...newActivities]);
|
|
|
|
const activityLogContainer = document.getElementById("activityLogContainer");
|
|
|
|
if (activityLogContainer) {
|
|
activityLogContainer.scrollTo({ top: 0, behavior: "smooth" });
|
|
}
|
|
},
|
|
[activityLog],
|
|
);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
updateActivityLog: handleActivityLogUpdate,
|
|
}));
|
|
|
|
return (
|
|
<div className="overflow-y-auto max-h-96" id="activityLogContainer">
|
|
<div className="flex flex-col-reverse gap-2">
|
|
{activityLog.map((activity) => (
|
|
<div key={activity.id} className="flex gap-2 items-top">
|
|
<span className="flex-1/3 text-xs text-gray-300 whitespace-nowrap mt-1.5">{formatter.format(activity.timestamp)}: </span>
|
|
<span className="flex-2/3 text-white whitespace-normal">{activity.activity}</span>
|
|
</div>
|
|
))}
|
|
{!activityLog.length && <span className="text-white">No activity logged.</span>}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|