= ({ model }) => {
{model.user.username}
- Last Modified:{" "}
+ {APP_CONTENT.models.modelsList.modelCard.lastModified}{" "}
{extractDatePart(model.last_modified)}
diff --git a/frontend/src/features/models/components/model-details-info.tsx b/frontend/src/features/models/components/model-details-info.tsx
index 39a4bfa9..bc406e34 100644
--- a/frontend/src/features/models/components/model-details-info.tsx
+++ b/frontend/src/features/models/components/model-details-info.tsx
@@ -1,11 +1,11 @@
import { ButtonWithIcon } from "@/components/ui/button";
import { DirectoryIcon, MapIcon } from "@/components/ui/icons";
-import { formatDate, truncateString } from "@/utils";
-import ModelDetailItem from "./model-detail-item";
-import ModelDetailsSection from "./model-details-section";
+import { APP_CONTENT, formatDate, truncateString } from "@/utils";
+import ModelDetailItem from "@/features/models/components/model-detail-item";
+import ModelDetailsSection from "@/features/models/components/model-details-section";
import ChevronDownIcon from "@/components/ui/icons/chevron-down";
import { Divider } from "@/components/ui/divider";
-import ModelFeedbacks from "./model-feedbacks";
+import ModelFeedbacks from "@/features/models/components/model-feedbacks";
const ModelDetailsInfo = ({
data,
@@ -20,7 +20,9 @@ const ModelDetailsInfo = ({
-
Model ID: {data?.id}
+
+ {APP_CONTENT.models.modelsDetailsCard.modelId} {data?.id}
+
- {data?.description ?? "Model description is not available."}
+ {data?.description ??
+ APP_CONTENT.models.modelsDetailsCard
+ .modelDescriptionNotAvailable}
- View Training Area
+ {APP_CONTENT.models.modelsDetailsCard.viewTrainingArea}
@@ -57,23 +61,28 @@ const ModelDetailsInfo = ({
-
+
- Training ID:
+
+ {APP_CONTENT.models.modelsDetailsCard.trainingId}{" "}
+
Training_{data?.published_training}
= ({
) : (
{value ?? "N/A"}
@@ -110,50 +113,86 @@ const ModelProperties: React.FC = ({
return (
+
-
{/* Animate the status when it's in progress. */}
{isTrainingDetailsDialog && (
)}
@@ -209,7 +248,7 @@ const FailedTrainingTraceBack = ({ taskId }: { taskId: string }) => {
role="button"
className="flex items-center gap-x-2"
>
-
Logs
+
{APP_CONTENT.models.modelsDetailsCard.trainingInfoDialog.logs}
{showLogs &&
}
diff --git a/frontend/src/features/models/components/model-feedbacks.tsx b/frontend/src/features/models/components/model-feedbacks.tsx
index 43715b5d..ad3655fa 100644
--- a/frontend/src/features/models/components/model-feedbacks.tsx
+++ b/frontend/src/features/models/components/model-feedbacks.tsx
@@ -1,6 +1,7 @@
import { ButtonWithIcon } from "@/components/ui/button";
import { ChatbubbleIcon } from "@/components/ui/icons";
-import { useTrainingFeedbacks } from "../hooks/use-training";
+import { useTrainingFeedbacks } from "@/features/models/hooks/use-training";
+import { APP_CONTENT } from "@/utils";
const ModelFeedbacks = ({ trainingId }: { trainingId: number }) => {
const { data, isLoading, isError } = useTrainingFeedbacks(trainingId);
@@ -13,11 +14,13 @@ const ModelFeedbacks = ({ trainingId }: { trainingId: number }) => {
<>
{isError ? "N/A" : data?.count}
- Feedbacks
+
+ {APP_CONTENT.models.modelsDetailsCard.feedbacks}
+
= ({
};
return (
-
+
{_offset + 1} -{" "}
diff --git a/frontend/src/features/models/components/training-history-table.tsx b/frontend/src/features/models/components/training-history-table.tsx
index 7b90f262..027ad8f2 100644
--- a/frontend/src/features/models/components/training-history-table.tsx
+++ b/frontend/src/features/models/components/training-history-table.tsx
@@ -1,7 +1,8 @@
-import { useTrainingHistory } from "../hooks/use-training";
+import { useTrainingHistory } from "@/features/models/hooks/use-training";
import { DataTable } from "@/components/ui/data-table";
import { TBadgeVariants, TTrainingDetails } from "@/types";
import {
+ APP_CONTENT,
formatDate,
formatDuration,
roundNumber,
@@ -9,8 +10,8 @@ import {
} from "@/utils";
import { ColumnDef, SortingState } from "@tanstack/react-table";
import { useState } from "react";
-import { SortableHeader } from "./table-header";
-import { TableSkeleton } from "./skeletons";
+import { SortableHeader } from "@/features/models/components/table-header";
+import { TableSkeleton } from "@/features/models/components/skeletons";
import { DropDown } from "@/components/ui/dropdown";
import { useDropdownMenu } from "@/hooks/use-dropdown-menu";
import { useAuth } from "@/app/providers/auth-provider";
@@ -18,10 +19,12 @@ import { Badge } from "@/components/ui/badge";
import CheckIcon from "@/components/ui/icons/check-icon";
import { ElipsisIcon, InfoIcon } from "@/components/ui/icons";
import { useDialog } from "@/hooks/use-dialog";
-import { TrainingDetailsDialog } from "./dialogs";
-import { useUpdateTraining } from "../api/update-trainings";
+import { TrainingDetailsDialog } from "@/features/models/components/dialogs";
+import { useUpdateTraining } from "@/features/models/api/update-trainings";
import { useToast } from "@/app/providers/toast-provider";
-import Pagination, { PAGE_LIMIT } from "./pagination";
+import Pagination, {
+ PAGE_LIMIT,
+} from "@/features/models/components/pagination";
type TrainingHistoryTableProps = {
modelId: string;
@@ -42,7 +45,9 @@ const columnDefinitions = (
header: ({ column }) => ,
},
{
- header: "Epochs / Batch Size",
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader
+ .epochAndBatchSize,
accessorFn: (row) => `${row.epochs}/${row.batch_size}`,
cell: (row) => (
{row.getValue() as string}
@@ -50,20 +55,24 @@ const columnDefinitions = (
},
{
accessorKey: "started_at",
- header: "Started At",
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader.startedAt,
cell: ({ row }) => {
return {formatDate(row.getValue("started_at"))};
},
},
{
accessorKey: "user.username",
- header: "Submitted by",
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader
+ .sumittedBy,
cell: ({ row }) => {
return {truncateString(row.original.user.username)};
},
},
{
- header: "Duration",
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader.duration,
accessorFn: (row) =>
formatDuration(new Date(row.started_at), new Date(row.finished_at)),
cell: (row) => (
@@ -72,7 +81,8 @@ const columnDefinitions = (
},
{
accessorKey: "input_contact_spacing",
- header: "DS Size",
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader.dsSize,
cell: ({ row }) => {
return {row.getValue("input_contact_spacing") ?? 0};
},
@@ -80,7 +90,13 @@ const columnDefinitions = (
{
accessorKey: "accuracy",
header: ({ column }) => (
-
+
),
cell: ({ row }) => {
return (
@@ -93,7 +109,8 @@ const columnDefinitions = (
},
},
{
- header: "Status",
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader.status,
accessorKey: "status",
cell: (row) => {
const statusToVariant: Record = {
@@ -117,8 +134,9 @@ const columnDefinitions = (
},
},
{
- header: "In Use",
- // accessorFn: row => row.freeze_layers,
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader.inUse,
+
cell: ({ row }) => {
return (
@@ -134,8 +152,10 @@ const columnDefinitions = (
...(modelOwner !== authUsername
? [
{
- header: "Info",
- // accessorFn: (row: TTrainingDetails) => row.multimasks,
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader
+ .info,
+
cell: ({ row }: { row: any }) => {
return (
row.model,
+ header:
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader
+ .action,
+
cell: ({ row }: { row: any }) => {
const { dropdownIsOpened, onDropdownHide, onDropdownShow } =
useDropdownMenu();
@@ -245,7 +267,14 @@ const TrainingHistoryTable: React.FC = ({
/>
-
{data?.count} Training History
+
+ {" "}
+ {data?.count}{" "}
+ {
+ APP_CONTENT.models.modelsDetailsCard.trainingHistoryTableHeader
+ .trainingHistoryCount
+ }
+
{
+/**
+ * Custom hook to detect if the current browser is Google Chrome.
+ *
+ * @returns { isChrome: boolean } - An object containing a boolean value indicating if the browser is Chrome.
+ *
+ */
+const useBrowserType = (): { isChrome: boolean } => {
const isChrome = useMemo(() => {
return (
/Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor)
@@ -9,3 +15,5 @@ export const useBrowserType = (): { isChrome: boolean } => {
return { isChrome };
};
+
+export default useBrowserType;
diff --git a/frontend/src/hooks/use-debounce.ts b/frontend/src/hooks/use-debounce.ts
index 8177e801..9304a316 100644
--- a/frontend/src/hooks/use-debounce.ts
+++ b/frontend/src/hooks/use-debounce.ts
@@ -1,6 +1,17 @@
import { useState, useEffect } from "react";
-function useDebounce(value: string, delay: number): string {
+/**
+ * Custom hook that debounces a value. This hook delays updating the value
+ * until after a specified delay period has passed without changes.
+ *
+ * @param value - The value that will be debounced.
+ * @param delay - The debounce delay in milliseconds.
+ *
+ * @returns {string} debouncedValue - The debounced value, updated after the delay.
+ *
+ */
+
+const useDebounce = (value: string, delay: number): string => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
@@ -13,6 +24,6 @@ function useDebounce(value: string, delay: number): string {
}, [value, delay]);
return debouncedValue;
-}
+};
export default useDebounce;
diff --git a/frontend/src/hooks/use-device.ts b/frontend/src/hooks/use-device.ts
index cffa0335..937ec09f 100644
--- a/frontend/src/hooks/use-device.ts
+++ b/frontend/src/hooks/use-device.ts
@@ -1,6 +1,15 @@
import { useEffect, useState } from "react";
-export const useDevice = () => {
+/**
+ * Custom hook to detect whether the current device is mobile based on the window width.
+ *
+ * This hook tracks the window width and returns `true` if the width is less than 768 pixels,
+ * indicating a mobile device, and `false` otherwise. It dynamically updates as the window is resized.
+ *
+ * @returns {boolean} isMobile - A boolean indicating whether the current device is considered mobile.
+ *
+ */
+const useDevice = () => {
const [isMobile, setIsMobile] = useState(false);
const handleResize = () => {
@@ -18,3 +27,5 @@ export const useDevice = () => {
return isMobile;
};
+
+export default useDevice;
diff --git a/frontend/src/hooks/use-dialog.ts b/frontend/src/hooks/use-dialog.ts
index db36234a..d50048b4 100644
--- a/frontend/src/hooks/use-dialog.ts
+++ b/frontend/src/hooks/use-dialog.ts
@@ -1,5 +1,14 @@
import { useCallback, useState } from "react";
+/**
+ * Custom hook to manage the state of a dialog (open/close).
+ *
+ * @returns {Object}
+ * - `isOpened: boolean`: A boolean indicating if the dialog is currently open.
+ * - `toggle: () => void`: A function to toggle the dialog's state (open/close).
+ * - `closeDialog: () => void`: A function to explicitly close the dialog.
+ * - `openDialog: () => void`: A function to explicitly open the dialog.
+ */
export const useDialog = () => {
const [isOpened, setIsOpened] = useState(false);
diff --git a/frontend/src/hooks/use-dropdown-menu.ts b/frontend/src/hooks/use-dropdown-menu.ts
index 0ccad661..05be6267 100644
--- a/frontend/src/hooks/use-dropdown-menu.ts
+++ b/frontend/src/hooks/use-dropdown-menu.ts
@@ -1,10 +1,17 @@
import { useCallback, useMemo, useState } from "react";
/**
- * This hook is to be used to handle the dropdown menu element events.
- * @returns Object
+ * Custom hook to manage the visibility state of a dropdown menu.
+ *
+ * This hook provides a simple way to control the opening and closing of a dropdown
+ * menu, offering functions to show and hide the dropdown, and a memoized value
+ * to track its current visibility state.
+ *
+ * @returns {Object}
+ * - `onDropdownShow: () => void`: Function to show/open the dropdown menu.
+ * - `onDropdownHide: () => void`: Function to hide/close the dropdown menu.
+ * - `dropdownIsOpened: boolean`: A memoized boolean that represents whether the dropdown is currently opened.
*/
-
export const useDropdownMenu = () => {
const [isOpened, setIsOpened] = useState(false);
const onDropdownShow = useCallback(() => {
diff --git a/frontend/src/hooks/use-login.ts b/frontend/src/hooks/use-login.ts
index fc340a71..aa66cf3c 100644
--- a/frontend/src/hooks/use-login.ts
+++ b/frontend/src/hooks/use-login.ts
@@ -6,8 +6,17 @@ import { useState } from "react";
import { useToast } from "@/app/providers/toast-provider";
/**
- * This hook is to be used to handle the login button click event. It encapsulate the actions that's necessary to be performed when the login button is clicked.
- * @returns Promise
+ * Custom hook to handle the login button click event.
+ *
+ * This hook encapsulates the actions that need to be performed when the login button is clicked,
+ * such as starting the OAuth login flow, handling the loading state, and showing error notifications.
+ * It also stores the current page's path in session storage so that the user can be redirected back
+ * after successful authentication.
+ *
+ * @returns {Object}
+ * - `loading: boolean`: Indicates whether the login process is in progress.
+ * - `handleLogin: () => Promise`: Function to handle the login button click event, initiating the OAuth flow.
+ *
*/
export const useLogin = () => {
const location = useLocation();
diff --git a/frontend/src/hooks/use-storage.ts b/frontend/src/hooks/use-storage.ts
index c3c5c6ec..99aface8 100644
--- a/frontend/src/hooks/use-storage.ts
+++ b/frontend/src/hooks/use-storage.ts
@@ -1,6 +1,13 @@
/**
- * This hook is used to manage the retrieval, creation and deletion of objects in the localstorage.
- * @returns getValue(), setValue(), removeValue().
+ * Custom hook to interact with the browser's localStorage.
+ *
+ * This hook provides utility functions to get, set, and remove items from the localStorage.
+ * It wraps the localStorage methods with error handling to avoid potential exceptions.
+ *
+ * @returns {Object}
+ * - `getValue: (key: string) => string | undefined`: Retrieves the stored value for the provided key.
+ * - `setValue: (key: string, value: string) => void`: Saves a value for the provided key in localStorage.
+ * - `removeValue: (key: string) => void`: Removes the value associated with the provided key from localStorage
*/
export const useLocalStorage = () => {
const getValue = (key: string): string | undefined => {
@@ -33,8 +40,15 @@ export const useLocalStorage = () => {
};
/**
- * This hook is used to manage the retrieval, creation and deletion of objects in the session storage.
- * @returns getValue(), setValue(), removeValue().
+ * Custom hook to interact with the browser's sessionStorage.
+ *
+ * This hook provides utility functions to get, set, and remove items from the sessionStorage.
+ * It wraps the sessionStorage methods with error handling to avoid potential exceptions.
+ *
+ * @returns {Object}
+ * - `getValue: (key: string) => string | undefined`: Retrieves the stored value for the provided key.
+ * - `setValue: (key: string, value: string) => void`: Saves a value for the provided key in sessionStorage.
+ * - `removeValue: (key: string) => void`: Removes the value associated with the provided key from sessionStorage
*/
export const useSessionStorage = () => {
const getValue = (key: string): string | undefined => {
diff --git a/frontend/src/services/api-client.ts b/frontend/src/services/api-client.ts
index bf552d8a..dc7d7ebf 100644
--- a/frontend/src/services/api-client.ts
+++ b/frontend/src/services/api-client.ts
@@ -33,7 +33,6 @@ apiClient.interceptors.response.use(
console.error("Unauthorized, logging out...");
localStorage.removeItem(HOT_FAIR_LOCAL_STORAGE_ACCESS_TOKEN_KEY);
}
- // should we handle more errors here?
return Promise.reject(error);
},
);
diff --git a/frontend/src/services/react-query.ts b/frontend/src/services/react-query.ts
index 94f1bb2e..111aad14 100644
--- a/frontend/src/services/react-query.ts
+++ b/frontend/src/services/react-query.ts
@@ -2,7 +2,6 @@ import { UseMutationOptions, DefaultOptions } from "@tanstack/react-query";
export const queryConfig = {
queries: {
- // throwOnError: true,
refetchOnWindowFocus: false,
retry: false,
staleTime: 1000 * 60,
diff --git a/frontend/src/styles/index.css b/frontend/src/styles/index.css
index 0d3a50e0..992efcf2 100644
--- a/frontend/src/styles/index.css
+++ b/frontend/src/styles/index.css
@@ -51,7 +51,7 @@ body {
/* 80px */
}
-/* Overriding the toast design to match figma design */
+/* Overriding the toast design style begins */
sl-alert::part(close-button__base),
sl-alert::part(close-button__base):hover {
@@ -93,7 +93,9 @@ sl-alert.success::part(base) {
border-color: var(--hot-fair-toast-success-color);
}
-/* Matomo placement */
+/* Overriding the toast design styles ends*/
+
+/* Matomo placement style begins */
.hot-matomo {
position: fixed;
@@ -102,7 +104,9 @@ sl-alert.success::part(base) {
width: 100vw;
}
-/* Toast stack placement */
+/* Matomo placement style ends */
+
+/* Toast stack placement style begins */
.sl-toast-stack {
left: 0;
@@ -111,7 +115,9 @@ sl-alert.success::part(base) {
bottom: 0;
}
-/* Icon styles */
+/* Toast stack placement style ends */
+
+/* Icon styles begins */
@layer components {
.icon {
@apply inline-block h-4 w-4;
@@ -121,3 +127,5 @@ sl-alert.success::part(base) {
@apply inline-block h-6 w-6;
}
}
+
+/* Icon styles ends */
diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts
index e0d0cec3..48c168fc 100644
--- a/frontend/src/types/api.ts
+++ b/frontend/src/types/api.ts
@@ -2,7 +2,7 @@
* This file contains the different types/schema for the API responses from the backend.
*/
-// Auth and User types
+// Auth and User API response types
export type TLogin = {
login_url: string;
@@ -31,7 +31,7 @@ type TOSMUser = {
username: string;
};
-// Model types
+// Models API response types
export type TModel = {
id: string;
name: string;
@@ -67,7 +67,7 @@ export type TModelDetails = TModel & {
description: string;
};
-// Training types
+// Training API response types
export type TTrainingDetails = {
id: number;
@@ -98,7 +98,7 @@ export type TTrainingStatus = {
status: "PENDING";
traceback: string;
};
-// Training workspace
+// Training workspace API response types
export type TrainingWorkspace = {
dir: Record>;
@@ -111,7 +111,7 @@ export type TTrainingFeedbacks = {
results: FeatureCollection;
};
-// Centroid types
+// Centroid API response types
export type Geometry = {
type:
diff --git a/frontend/src/types/common.ts b/frontend/src/types/common.ts
index 28e74d2a..7b52a2a6 100644
--- a/frontend/src/types/common.ts
+++ b/frontend/src/types/common.ts
@@ -14,3 +14,12 @@ export type DateFilter = {
export type TQueryParams = Record;
export type TBadgeVariants = "green" | "red" | "yellow" | "blue" | "default";
+
+export type ButtonVariant =
+ | "primary"
+ | "secondary"
+ | "tertiary"
+ | "default"
+ | "dark";
+
+export type ButtonSize = "large" | "medium" | "small";
diff --git a/frontend/src/utils/content.ts b/frontend/src/utils/content.ts
index 6d16e943..db315208 100644
--- a/frontend/src/utils/content.ts
+++ b/frontend/src/utils/content.ts
@@ -188,4 +188,97 @@ export const APP_CONTENT = {
loginSuccess: "Login successful.",
logoutSuccess: "Logout successful.",
},
+ models: {
+ modelsList: {
+ pageTitle: "fAIr AI models",
+ description: `Each model is trained using one of the training datasets. Published models can be used to find mappable features in imagery that is similar to the training areas that dataset comes from.`,
+ ctaButton: "Create Model",
+ filtersSection: {
+ searchPlaceHolder: "Search",
+ mapViewToggleText: "Map View",
+ },
+ sortingAndPaginationSection: {
+ modelCountSuffix: "models",
+ sortingTitle: "Sort by",
+ },
+ modelCard: {
+ accuracy: "Accuracy:",
+ lastModified: "Last Modified:",
+ },
+ },
+ modelsDetailsCard: {
+ modelId: "Model ID",
+ detailsSectionTitle: "Details",
+ createdBy: "Created By",
+ createdOn: "Created On",
+ lastModified: "Last Modified",
+ trainingId: "Training ID:",
+ propertiesSectionTitle: "Properties",
+ trainingHistorySectionTitle: "Training History",
+ submitTrainingRequest: "Submit a training request",
+ feedbacks: " Feedbacks",
+ startMapping: "Start Mapping",
+ modelDescriptionNotAvailable: "Model description is not available.",
+ viewTrainingArea: "View Training Area",
+ viewFeedbacks: "View Feedbacks",
+ modelFiles: "Model Files",
+ properties: {
+ zoomLevels: {
+ title: "Zoom Levels",
+ tooltip: "",
+ },
+ epochs: {
+ title: "Epochs",
+ tooltip: "",
+ },
+ contactSpacing: {
+ title: "Contact Spacing",
+ tooltip: "",
+ },
+ currentDatasetSize: {
+ title: "Current Dataset Size",
+ tooltip: "",
+ },
+ sourceImage: {
+ title: "Source Image (TMS)",
+ tooltip: "",
+ },
+ batchSize: {
+ title: "Batch Size",
+ tooltip: "",
+ },
+ accuracy: {
+ title: "Accuracy",
+ tooltip: "",
+ },
+ boundaryWidth: {
+ title: "Boundary Width",
+ tooltip: "",
+ },
+ },
+ trainingHistoryTableHeader: {
+ trainingHistoryCount: "Training History",
+ id: "ID",
+ epochAndBatchSize: "Epochs / Batch Size",
+ startedAt: "Started At",
+ sumittedBy: "Submitted by",
+ duration: "Duration",
+ dsSize: "DS Size",
+ accuracy: "Accuracy (%)",
+ status: "Status",
+ info: "Info",
+ action: "Action",
+ inUse: "In Use",
+ },
+ modelFilesDialog: {
+ rootDirectory: "Root Directory",
+ dialogTitle: "Model Files",
+ error: "Error loading directories.",
+ },
+ trainingInfoDialog: {
+ status: "Status",
+ logs: "Logs",
+ },
+ },
+ },
};
diff --git a/frontend/src/utils/date-utils.ts b/frontend/src/utils/date-utils.ts
index 4afdf054..75218df4 100644
--- a/frontend/src/utils/date-utils.ts
+++ b/frontend/src/utils/date-utils.ts
@@ -1,9 +1,41 @@
import { DateFilter } from "@/types";
+/**
+ * Extracts the date part from an ISO 8601 date-time string.
+ *
+ * This function takes an ISO date-time string (e.g., "2024-01-01T12:00:00Z")
+ * and splits it at the "T" character to isolate the date portion.
+ * It returns the date part in the format "YYYY-MM-DD".
+ *
+ * @param {string} isoString - The ISO date-time string to extract the date from.
+ * @returns {string} - The extracted date part in "YYYY-MM-DD" format.
+ */
export const extractDatePart = (isoString: string) => {
return isoString.split("T")[0];
};
+/**
+ * Constructs a query string object for filtering records based on date range.
+ *
+ * This function takes an optional date filter and two optional date strings
+ * (startDate and endDate) and builds a record of query parameters to be used
+ * in an API request. The resulting query parameters will use the API value of
+ * the selected filter along with `__gte` (greater than or equal) and `__lte`
+ * (less than or equal) suffixes for the respective dates.
+ *
+ * - If `startDate` is provided, it adds a query parameter for the lower bound.
+ * - If `endDate` is provided, it adds a query parameter for the upper bound.
+ * - If neither date is provided, an empty object is returned.
+ *
+ * @param {DateFilter} [selectedFilter] - The filter object containing the API value.
+ * @param {string} [startDate] - The starting date string in ISO format.
+ * @param {string} [endDate] - The ending date string in ISO format.
+ * @returns {Record} - An object containing the query parameters for filtering.
+ *
+ * Example usage:
+ * const query = buildDateFilterQueryString(selectedFilter, '2024-01-01', '2024-12-31');
+ * Output: { "filterField__gte": "2024-01-01", "filterField__lte": "2024-12-31" }
+ */
export const buildDateFilterQueryString = (
selectedFilter?: DateFilter,
startDate?: string,
@@ -33,6 +65,15 @@ export const formatDate = (isoString: string): string => {
return `${day}/${month}/${year}, ${hours}:${minutes}:${seconds}`;
};
+/**
+ * Formats the duration between two Date objects (startDate and endDate) into a human-readable string.
+ *
+ * The function calculates the absolute difference between the two dates and converts it into hours, minutes, and seconds.
+ * It then formats the duration into a string such as "Xhr Y Mins Z Secs" depending on which time units are present.
+ * @param {Date} startDate - The starting date and time.
+ * @param {Date} endDate - The ending date and time.
+ * @returns {string} - The formatted duration string (e.g., "2hr 15 Mins 30 Secs").
+ */
export const formatDuration = (startDate: Date, endDate: Date): string => {
const diff = Math.abs(endDate.getTime() - startDate.getTime());
diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts
index a2feb02d..80451aa3 100644
--- a/frontend/src/utils/index.ts
+++ b/frontend/src/utils/index.ts
@@ -1,7 +1,6 @@
export * from "./cn";
export * from "./constants";
export * from "./content";
-export * from "./types";
export * from "./date-utils";
export * from "./number-utils";
export * from "./string-utils";
diff --git a/frontend/src/utils/number-utils.ts b/frontend/src/utils/number-utils.ts
index 0371e5d8..0d03b7aa 100644
--- a/frontend/src/utils/number-utils.ts
+++ b/frontend/src/utils/number-utils.ts
@@ -1,3 +1,14 @@
+/**
+ * Rounds a number to a specified number of decimal places.
+ *
+ * This function takes a number and rounds it to a defined number of decimal places,
+ * returning it as a string. By default, it rounds to two decimal places, but this can
+ * be adjusted by providing a different value for the `round` parameter.
+ *
+ * @param {number} num - The number to be rounded.
+ * @param {number} [round=2] - The number of decimal places to round to (default is 2).
+ * @returns {string} - The rounded number as a string.
+ */
export const roundNumber = (num: number, round: number = 2) => {
return num.toFixed(round) ?? 0;
};
diff --git a/frontend/src/utils/string-utils.ts b/frontend/src/utils/string-utils.ts
index 3e90ed0d..e774cca8 100644
--- a/frontend/src/utils/string-utils.ts
+++ b/frontend/src/utils/string-utils.ts
@@ -1,3 +1,14 @@
+/**
+ * Truncates a string to a specified maximum length, appending ellipsis if truncated.
+ *
+ * This function takes a string and a maximum length, and if the string exceeds
+ * the specified length, it truncates the string and appends "..." to indicate that
+ * it has been shortened. The default maximum length is set to 30 characters.
+ *
+ * @param {string} [string] - The string to be truncated (optional).
+ * @param {number} [maxLength=30] - The maximum length for the string (default is 30).
+ * @returns {string | undefined} - The truncated string with ellipsis, or the original string if within limit.
+ */
export const truncateString = (string?: string, maxLength: number = 30) => {
if (string && string.length > maxLength) {
return `${string.slice(0, maxLength - 3)}...`;
diff --git a/frontend/src/utils/types.ts b/frontend/src/utils/types.ts
deleted file mode 100644
index 2cd802de..00000000
--- a/frontend/src/utils/types.ts
+++ /dev/null
@@ -1 +0,0 @@
-export interface IconProps extends React.SVGProps {}