feat(task-time-logs): enhance time log retrieval and formatting with user timezone
- Integrated user timezone handling in the task time logs API service to ensure accurate time representation. - Added a new utility function to format date/time strings according to the user's profile timezone. - Updated the TimeLogItem component to utilize the new formatting function for displaying timestamps.
This commit is contained in:
@@ -2,6 +2,7 @@ import { API_BASE_URL } from '@/shared/constants';
|
||||
import apiClient from '../api-client';
|
||||
import { IServerResponse } from '@/types/common.types';
|
||||
import { ITaskLogViewModel } from '@/types/tasks/task-log-view.types';
|
||||
import { getUserSession } from '@/utils/session-helper';
|
||||
|
||||
const rootUrl = `${API_BASE_URL}/task-time-log`;
|
||||
|
||||
@@ -17,7 +18,11 @@ export interface IRunningTimer {
|
||||
|
||||
export const taskTimeLogsApiService = {
|
||||
getByTask: async (id: string): Promise<IServerResponse<ITaskLogViewModel[]>> => {
|
||||
const response = await apiClient.get(`${rootUrl}/task/${id}`);
|
||||
const session = getUserSession();
|
||||
const timezone = session?.timezone_name || 'UTC';
|
||||
const response = await apiClient.get(`${rootUrl}/task/${id}`, {
|
||||
params: { time_zone_name: timezone }
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Button, Divider, Flex, Popconfirm, Typography, Space } from '@/shared/a
|
||||
import { colors } from '@/styles/colors';
|
||||
import { ITaskLogViewModel } from '@/types/tasks/task-log-view.types';
|
||||
import SingleAvatar from '@/components/common/single-avatar/single-avatar';
|
||||
import { formatDateTimeWithLocale } from '@/utils/format-date-time-with-locale';
|
||||
import { formatDateTimeWithUserTimezone } from '@/utils/format-date-time-with-user-timezone';
|
||||
import { calculateTimeGap } from '@/utils/calculate-time-gap';
|
||||
import './time-log-item.css';
|
||||
import { taskTimeLogsApiService } from '@/api/tasks/task-time-logs.api.service';
|
||||
@@ -101,7 +101,7 @@ const TimeLogItem = ({ log, onDelete }: TimeLogItemProps) => {
|
||||
{renderLoggedByTimer()} {calculateTimeGap(created_at || '')}
|
||||
</Typography.Text>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{formatDateTimeWithLocale(created_at || '')}
|
||||
{formatDateTimeWithUserTimezone(created_at || '', currentSession?.timezone_name)}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
{renderActionButtons()}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { format } from 'date-fns';
|
||||
import { enUS, es, pt } from 'date-fns/locale';
|
||||
import { getLanguageFromLocalStorage } from './language-utils';
|
||||
|
||||
/**
|
||||
* Formats a date/time string using the user's profile timezone
|
||||
* This ensures consistency between time logs display and reporting filters
|
||||
*
|
||||
* @param dateString - The date string to format (typically in UTC)
|
||||
* @param userTimezone - The user's timezone from their profile (e.g., 'America/New_York')
|
||||
* @returns Formatted date string in user's timezone
|
||||
*/
|
||||
export const formatDateTimeWithUserTimezone = (
|
||||
dateString: string,
|
||||
userTimezone?: string | null
|
||||
): string => {
|
||||
if (!dateString) return '';
|
||||
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
|
||||
// If timezone is provided, use it for formatting
|
||||
if (userTimezone && userTimezone !== 'UTC') {
|
||||
// Use the browser's toLocaleString with timezone option
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
timeZone: userTimezone,
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: true
|
||||
};
|
||||
|
||||
// Get the appropriate locale
|
||||
const localeString = getLanguageFromLocalStorage();
|
||||
const localeMap = {
|
||||
'en': 'en-US',
|
||||
'es': 'es-ES',
|
||||
'pt': 'pt-PT'
|
||||
};
|
||||
const locale = localeMap[localeString as keyof typeof localeMap] || 'en-US';
|
||||
|
||||
return date.toLocaleString(locale, options);
|
||||
}
|
||||
|
||||
// Fallback to date-fns formatting for UTC or when no timezone
|
||||
const localeString = getLanguageFromLocalStorage();
|
||||
const locale = localeString === 'en' ? enUS : localeString === 'es' ? es : pt;
|
||||
return format(date, 'MMM d, yyyy, h:mm:ss a', { locale });
|
||||
} catch (error) {
|
||||
console.error('Error formatting date with user timezone:', error);
|
||||
// Fallback to original date string if formatting fails
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a date is "yesterday" in the user's timezone
|
||||
* This is used to ensure consistency with reporting filters
|
||||
*
|
||||
* @param dateString - The date string to check
|
||||
* @param userTimezone - The user's timezone from their profile
|
||||
* @returns true if the date is yesterday in user's timezone
|
||||
*/
|
||||
export const isYesterdayInUserTimezone = (dateString: string, userTimezone?: string | null): boolean => {
|
||||
if (!dateString || !userTimezone) return false;
|
||||
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
|
||||
// Get current date in user's timezone
|
||||
const nowInTimezone = new Date().toLocaleString('en-US', { timeZone: userTimezone });
|
||||
const now = new Date(nowInTimezone);
|
||||
|
||||
// Get yesterday in user's timezone
|
||||
const yesterday = new Date(now);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
// Convert the input date to user's timezone
|
||||
const dateInTimezone = new Date(date.toLocaleString('en-US', { timeZone: userTimezone }));
|
||||
|
||||
// Compare dates (ignoring time)
|
||||
return (
|
||||
dateInTimezone.getFullYear() === yesterday.getFullYear() &&
|
||||
dateInTimezone.getMonth() === yesterday.getMonth() &&
|
||||
dateInTimezone.getDate() === yesterday.getDate()
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error checking if date is yesterday:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user