NUDR / frontend /src /components /ResearchProgressFooter.tsx
magicboris's picture
Upload 83 files
3647b02 verified
raw
history blame
3.6 kB
/*
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use client';
import { ChatBubbleLeftIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { useEffect, useState } from 'react';
import styles from './ResearchProgressFooter.module.css';
import { ApplicationState } from '@/types/ApplicationState';
interface ResearchProgressFooterProps {
state: ApplicationState;
}
const formatElapsedTime = (seconds: number): string => {
if (seconds < 60) {
return `${seconds}s`;
}
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
if (seconds < 3600) {
return `${minutes}m ${remainingSeconds}s`;
}
const hours = Math.floor(seconds / 3600);
const remainingMinutes = Math.floor((seconds % 3600) / 60);
return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
};
export default function ResearchProgressFooter({
state
}: ResearchProgressFooterProps) {
const isActive = state.type === 'researching' || state.type === 'finalizing';
const [elapsedTime, setElapsedTime] = useState(0);
useEffect(() => {
if (!isActive) {
// If we have an end timestamp, use it to calculate final elapsed time
let time = 0;
if (state.researchEndTimestamp > 0) {
time += Math.floor((state.researchEndTimestamp - state.researchStartTimestamp) / 1000);
if (state.finalizationEndTimestamp > 0) {
time += Math.floor((state.finalizationEndTimestamp - state.finalizationStartTimestamp) / 1000);
}
}
setElapsedTime(time);
return;
}
const interval = setInterval(() => {
const now = Date.now();
let startTime = 0;
let endTime = now;
let timePrefix = 0;
if (state.researchStartTimestamp > 0) {
startTime = state.researchStartTimestamp;
}
if (state.finalizationStartTimestamp > 0) {
startTime = state.finalizationStartTimestamp;
timePrefix = state.researchEndTimestamp - state.researchStartTimestamp;
if (state.finalizationEndTimestamp > 0) {
endTime = state.finalizationEndTimestamp;
}
}
const newTime = Math.floor((timePrefix + endTime - startTime) / 1000);
setElapsedTime(newTime);
}, 1000);
return () => clearInterval(interval);
}, [isActive, state.researchStartTimestamp, state.researchEndTimestamp, state.finalizationStartTimestamp, state.finalizationEndTimestamp]);
return (
<div className={styles.footer}>
<div className={styles.stats}>
<span className={styles.time}>{formatElapsedTime(elapsedTime)}</span>
<div className={styles.searchCount}>
<MagnifyingGlassIcon className={styles.searchIcon} />
<span>{state.searchCount}</span>
</div>
<div className={styles.queryCount}>
<ChatBubbleLeftIcon className={styles.queryIcon} />
<span>{state.queryCount}</span>
</div>
</div>
</div>
);
}