feat: add date formatting helper (#938)

This commit is contained in:
Michael Datelle
2024-10-25 10:43:38 -04:00
committed by GitHub
parent 0578b066f1
commit 5b2421cb0c
5 changed files with 52 additions and 7 deletions

View File

@@ -591,6 +591,7 @@ export function NotificationSchema(): z.ZodObject<Properties<Notification>> {
return z.object({
__typename: z.literal('Notification').optional(),
description: z.string(),
formattedTimestamp: z.string().nullish(),
id: z.string(),
importance: ImportanceSchema,
link: z.string().nullish(),

View File

@@ -817,6 +817,7 @@ export type Node = {
export type Notification = Node & {
__typename?: 'Notification';
description: Scalars['String']['output'];
formattedTimestamp?: Maybe<Scalars['String']['output']>;
id: Scalars['ID']['output'];
importance: Importance;
link?: Maybe<Scalars['String']['output']>;
@@ -2403,6 +2404,7 @@ export type NodeResolvers<ContextType = Context, ParentType extends ResolversPar
export type NotificationResolvers<ContextType = Context, ParentType extends ResolversParentTypes['Notification'] = ResolversParentTypes['Notification']> = ResolversObject<{
description?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
formattedTimestamp?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
importance?: Resolver<ResolversTypes['Importance'], ParentType, ContextType>;
link?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;

View File

@@ -17,15 +17,21 @@ type Query {
type Mutation {
createNotification(input: NotificationData!): Notification!
deleteNotification(id: String!, type: NotificationType!): NotificationOverview!
"""Marks a notification as archived."""
"""
Marks a notification as archived.
"""
archiveNotification(id: String!): Notification!
"""Marks a notification as unread."""
"""
Marks a notification as unread.
"""
unreadNotification(id: String!): Notification!
archiveNotifications(ids: [String!]): NotificationOverview!
unarchiveNotifications(ids: [String!]): NotificationOverview!
archiveAll(importance: Importance): NotificationOverview!
unarchiveAll(importance: Importance): NotificationOverview!
"""Reads each notification to recompute & update the overview."""
"""
Reads each notification to recompute & update the overview.
"""
recalculateOverview: NotificationOverview!
}
@@ -42,7 +48,9 @@ enum Importance {
type Notifications implements Node {
id: ID!
"""A cached overview of the notifications in the system & their severity."""
"""
A cached overview of the notifications in the system & their severity.
"""
overview: NotificationOverview!
list(filter: NotificationFilter!): [Notification!]!
}
@@ -62,6 +70,7 @@ type Notification implements Node {
ISO Timestamp for when the notification occurred
"""
timestamp: String
formattedTimestamp: String
}
input NotificationData {

View File

@@ -10,6 +10,7 @@ import { createSubscription, PUBSUB_CHANNEL } from '@app/core/pubsub';
import { NotificationsService } from './notifications.service';
import { Importance } from '@app/graphql/generated/client/graphql';
import { AppError } from '@app/core/errors/app-error';
import { formatTimestamp } from '@app/utils';
@Resolver('Notifications')
export class NotificationsResolver {
@@ -41,7 +42,11 @@ export class NotificationsResolver {
@Args('filter')
filters: NotificationFilter
) {
return await this.notificationsService.getNotifications(filters);
const notifications = await this.notificationsService.getNotifications(filters);
return notifications.map((notification) => ({
...notification,
formattedTimestamp: formatTimestamp(notification.timestamp),
}));
}
/**============================================
@@ -97,7 +102,9 @@ export class NotificationsResolver {
}
@Mutation()
public async unarchiveAll(@Args('importance') importance?: Importance): Promise<NotificationOverview> {
public async unarchiveAll(
@Args('importance') importance?: Importance
): Promise<NotificationOverview> {
const { overview } = await this.notificationsService.unarchiveAll(importance);
return overview;
}
@@ -106,7 +113,7 @@ export class NotificationsResolver {
public async recalculateOverview() {
const { overview, error } = await this.notificationsService.recalculateOverview();
if (error) {
throw new AppError("Failed to refresh overview", 500);
throw new AppError('Failed to refresh overview', 500);
}
return overview;
}

View File

@@ -101,3 +101,29 @@ export function updateObject(
iterations++;
}
}
/**
* Formats a timestamp into a human-readable format: "MMM D, YYYY"
* Example: "Oct 24, 2024"
*
* @param timestamp - ISO date string or Unix timestamp in seconds
* @returns Formatted date string or null if timestamp is invalid
*/
export function formatTimestamp(timestamp: string | number | null | undefined): string | null {
if (!timestamp) return null;
try {
// Convert Unix timestamp (seconds) to milliseconds if needed
const date = typeof timestamp === 'number' ? new Date(timestamp * 1_000) : new Date(timestamp);
if (isNaN(date.getTime())) return null;
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
});
} catch {
return null;
}
}