Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions components/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import moment from 'moment';
import React from 'react';
import { twMerge } from 'tailwind-merge';

import type { IEvent } from '@/types/event';
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';

import eventsData from '../config/meetings.json';
import { formatDate, formatDateWithTimezone, isDateAfter } from '../utils/dateHelpers';
import { useTranslation } from '../utils/i18n';
import { getEvents } from '../utils/staticHelpers';
import GoogleCalendarButton from './buttons/GoogleCalendarButton';
Expand All @@ -29,7 +29,7 @@ export default function Calendar({ className = '', size }: ICalendarProps) {
const CALENDAR_URL =
'https://calendar.google.com/calendar/embed?src=c_q9tseiglomdsj6njuhvbpts11c%40group.calendar.google.com&ctz=UTC';
const currentDate = new Date();
const eventsExist = eventsData?.filter((event: IEvent) => moment(event.date).isAfter(currentDate)).length > 0;
const eventsExist = eventsData?.filter((event: IEvent) => isDateAfter(event.date, currentDate)).length > 0;

return (
<div
Expand All @@ -46,13 +46,12 @@ export default function Calendar({ className = '', size }: ICalendarProps) {
<li key={index} data-testid='Calendar-list-item'>
<a href={event.url} className='mb-1 mt-2 flex grow flex-col items-start sm:flex-row sm:items-center'>
<div className='inline-flex h-12 min-w-12 flex-row rounded-full bg-pink-500 font-bold text-white'>
<span className='flex-1 self-center text-center'>{moment(event.date).format('D')}</span>
<span className='flex-1 self-center text-center'>{formatDate(event.date, 'd')}</span>
</div>
<div className='grow text-left sm:mt-0 sm:pl-6'>
<h2 className='title-font font-medium text-gray-900 hover:text-gray-500'>{event.title}</h2>
<p className='text-gray-600'>
{moment(event.date).local().format('LLLL')} UTC
{moment(event.date).local().format('Z')}
{formatDateWithTimezone(event.date)}
</p>
</div>
</a>
Expand Down
13 changes: 7 additions & 6 deletions components/campaigns/AnnouncementRemainingDays.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import moment from 'moment';
import React from 'react';

import { getDaysDifference, getHoursDifference, getMinutesDifference, parseDate } from '../../utils/dateHelpers';

interface AnnouncementRemainingDaysProps {
dateTime: string;
eventName: string;
Expand All @@ -12,11 +13,11 @@ interface AnnouncementRemainingDaysProps {
* @param {string} props.eventName - The name of the event
*/
export default function AnnouncementRemainingDays({ dateTime, eventName }: AnnouncementRemainingDaysProps) {
const date = moment(dateTime);
const now = moment();
const days = date.diff(now, 'days');
const hours = date.diff(now, 'hours');
const minutes = date.diff(now, 'minutes');
const date = parseDate(dateTime);
const now = new Date();
const days = getDaysDifference(date, now);
const hours = getHoursDifference(date, now);
const minutes = getMinutesDifference(date, now);

let text = '';

Expand Down
4 changes: 2 additions & 2 deletions components/layout/BlogLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import moment from 'moment';
import ErrorPage from 'next/error';
import HtmlHead from 'next/head';
import { useRouter } from 'next/router';
Expand All @@ -7,6 +6,7 @@ import React from 'react';
import type { IPosts } from '@/types/post';

import BlogContext from '../../context/BlogContext';
import { formatDate } from '../../utils/dateHelpers';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check frontmatter date fields in markdown files
fd -e md -e mdx | xargs rg -n '^date:\s*' -A 0 || true

Repository: asyncapi/website

Length of output: 12099


🏁 Script executed:

# Find and examine the formatDate implementation
fd -e ts -e tsx -e js -e jsx | xargs rg -l 'formatDate|parseISO' | head -20

Repository: asyncapi/website

Length of output: 321


🏁 Script executed:

# Get context around line 74 in BlogLayout.tsx
fd -e tsx | xargs grep -l 'BlogLayout' | head -1 | xargs sed -n '70,80p'

Repository: asyncapi/website

Length of output: 543


🏁 Script executed:

# Check dateHelpers implementation
fd -e ts -e tsx -e js -e jsx -path '*/utils/*' | xargs grep -l 'formatDate\|parseISO' || true

Repository: asyncapi/website

Length of output: 228


🏁 Script executed:

# Read dateHelpers.ts implementation
fd -name 'dateHelpers.ts' -o -name 'dateHelpers.js' | xargs cat

Repository: asyncapi/website

Length of output: 290


🏁 Script executed:

# Check how blog posts are loaded/parsed
fd -name '*blog*' -type f | xargs rg -l 'getAllPosts\|getBlogPosts\|frontmatter\|gray-matter' | head -5

Repository: asyncapi/website

Length of output: 290


🏁 Script executed:

# Search for blog data loading in pages or API routes
fd -name 'index.tsx' -o -name 'index.ts' | xargs rg -l 'blog\|post' | head -5

Repository: asyncapi/website

Length of output: 290


🏁 Script executed:

# Find and read dateHelpers.ts
find . -name 'dateHelpers.ts' -o -name 'dateHelpers.js' | head -1 | xargs cat

Repository: asyncapi/website

Length of output: 2086


🏁 Script executed:

# Search for blog data loading utilities
find . -type f -name '*.ts' -o -name '*.tsx' | xargs grep -l 'getAllPosts\|getBlogPosts' 2>/dev/null | head -5

Repository: asyncapi/website

Length of output: 234


🏁 Script executed:

# Check BlogLayout context around line 74 and 9
find . -name 'BlogLayout.tsx' | xargs cat

Repository: asyncapi/website

Length of output: 3720


🏁 Script executed:

# Find where blog posts are loaded/parsed
find . -type f \( -name '*.ts' -o -name '*.tsx' \) | xargs grep -l 'post.date\|getPosts\|getAllPosts' 2>/dev/null | head -10

Repository: asyncapi/website

Length of output: 410


🏁 Script executed:

# Check for blog data transformation/frontmatter parsing
find . -type f \( -name '*.ts' -o -name '*.tsx' \) | xargs grep -l 'frontmatter\|gray-matter\|parseISO' 2>/dev/null | head -10

Repository: asyncapi/website

Length of output: 188


🏁 Script executed:

# Look for the types definition to understand what post.date is
find . -type f -name 'post.ts' -o -name 'post.d.ts' -o -name '*.ts' | xargs grep -l 'interface IPosts\|type IPosts' 2>/dev/null | head -5

Repository: asyncapi/website

Length of output: 75


🏁 Script executed:

# Read the post types definition
cat ./types/post.ts

Repository: asyncapi/website

Length of output: 621


🏁 Script executed:

# Read build-post-list.ts to see date processing
cat ./scripts/build-post-list.ts

Repository: asyncapi/website

Length of output: 13127


🏁 Script executed:

# Check utils/api.ts for date handling
cat ./utils/api.ts

Repository: asyncapi/website

Length of output: 1359


Add error handling for date parsing in formatDate.
parseISO from date-fns will fail on non-ISO dates and return Invalid Date, which breaks both the rendered date display and the dateTime attribute. While most blog dates are ISO-8601 compliant, malformed dates with missing leading zeros (e.g., 7:26:58 instead of 07:26:58) have been found in the frontmatter and will cause rendering issues. Add a fallback to gracefully handle parsing failures:

export function formatDate(date: string | Date, formatStr: string): string {
  let parsedDate: Date;
  try {
    parsedDate = typeof date === 'string' ? parseISO(date) : date;
  } catch (e) {
    parsedDate = new Date(date); // fallback to native Date parsing
  }
  return isValid(parsedDate) ? format(parsedDate, formatStr) : 'Invalid date';
}

Also applies to: 74-74

🤖 Prompt for AI Agents
In `@components/layout/BlogLayout.tsx` at line 9, The formatDate helper currently
uses parseISO and can produce an Invalid Date for non-ISO inputs; update
formatDate to catch parse errors and fall back to native Date parsing, then
verify validity with isValid before formatting: in the formatDate function (and
any duplicate at line ~74), try parsing with parseISO for strings but catch
exceptions and assign new Date(date) as a fallback, then return
format(parsedDate, formatStr) only if isValid(parsedDate), otherwise return a
safe placeholder like 'Invalid date' to avoid broken rendered output and invalid
dateTime attributes.

import AuthorAvatars from '../AuthorAvatars';
import AnnouncementHero from '../campaigns/AnnouncementHero';
import Head from '../Head';
Expand Down Expand Up @@ -71,7 +71,7 @@ export default function BlogLayout({ post, children }: IBlogLayoutProps) {
</span>
</p>
<div className='flex text-sm leading-5 text-gray-500'>
<time dateTime={post.date}>{moment(post.date).format('MMMM D, YYYY')}</time>
<time dateTime={post.date}>{formatDate(post.date, 'MMMM d, yyyy')}</time>
<span className='mx-1'>&middot;</span>
<span>{post.readingTime} min read</span>
</div>
Expand Down
4 changes: 2 additions & 2 deletions components/navigation/BlogPostItem.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import moment from 'moment';
import Link from 'next/link';
import type { Ref } from 'react';
import React, { forwardRef } from 'react';
import TextTruncate from 'react-text-truncate';

import { BlogPostType } from '@/types/components/navigation/BlogPostType';
import { formatDate } from '@/utils/dateHelpers';
import type { IBlogPost } from '@/types/post';
Comment on lines 1 to 7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Import order is failing CI.
The pipeline reports “Run autofix to sort these imports!”. Please run the repo’s import‑sorting autofix or reorder imports to satisfy lint.

🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 1-1: Run autofix to sort these imports!

🤖 Prompt for AI Agents
In `@components/navigation/BlogPostItem.tsx` around lines 1 - 8, The import order
in BlogPostItem.tsx fails CI; reorder imports (or run the repo's import-sorting
autofix) so external packages come first (react, next, react-text-truncate),
then type imports, then local project imports—ensuring Link, React/forwardRef,
TextTruncate are grouped before BlogPostType, formatDate, and IBlogPost; run the
project's autofix (e.g., yarn/npm script or eslint --fix) after reordering to
satisfy the linter.

import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';
Expand Down Expand Up @@ -129,7 +129,7 @@ const BlogPostItem = ({ post, className = '', id = '' }: BlogPostItemProps, ref:
</span>
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.sm} className='flex'>
<time dateTime={post.date}>{moment(post.date).format('MMMM D, YYYY')}</time>
<time dateTime={post.date}>{formatDate(post.date, 'MMMM d, yyyy')}</time>
<span className='mx-1'>&middot;</span>
<span>{post.readingTime} min read</span>
</Paragraph>
Expand Down
9 changes: 4 additions & 5 deletions components/navigation/EventFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import moment from 'moment';
import React, { useEffect, useState } from 'react';

import type { IEvent } from '@/types/event';
import { formatDate, isDateAfter, isDateBefore } from '@/utils/dateHelpers';

import { getEvents } from '../../utils/staticHelpers';

Expand All @@ -23,8 +23,7 @@ interface EventFilterProps {
* @param {React.Dispatch<React.SetStateAction<IEvent[]>>} props.setData - The function to update the filtered events.
*/
export default function EventFilter({ data, setData }: EventFilterProps) {
const localTime = moment().format('YYYY-MM-DD');
const currentDate = `${localTime}T00:00:00.000Z`;
const currentDate = new Date();
const filterList: string[] = ['All', 'Upcoming', 'Recorded'];
const [active, setActive] = useState<string>('All');

Expand All @@ -36,14 +35,14 @@ export default function EventFilter({ data, setData }: EventFilterProps) {
case ActiveState.Upcoming:
setData(
getEvents(data).filter((event: IEvent) => {
return moment(event.date).format() > currentDate;
return isDateAfter(event.date, currentDate);
})
);
break;
case ActiveState.Recorded:
setData(
getEvents(data).filter((event: IEvent) => {
return moment(event.date).format() < currentDate;
return isDateBefore(event.date, currentDate);
})
);
break;
Expand Down
21 changes: 11 additions & 10 deletions components/navigation/EventPostItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ArrowRightIcon } from '@heroicons/react/outline';
import moment from 'moment';
import React from 'react';

import type { IEvent } from '@/types/event';
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { formatDate, isDateBefore, parseDate } from '@/utils/dateHelpers';

import IconCalendar from '../icons/Calendar';
import Community from '../icons/Community';
Expand All @@ -25,8 +25,7 @@ interface EventPostItemProps {
*
*/
function EventPostItem({ post, className = '', id }: EventPostItemProps): React.JSX.Element {
const localTime = moment().format('YYYY-MM-DD'); // store localTime
const currentDate = `${localTime}T00:00:00.000Z`;
const currentDate = new Date();
const title = post.title || '';
let color = '';
let icon: React.ReactElement | null = null;
Expand All @@ -48,12 +47,14 @@ function EventPostItem({ post, className = '', id }: EventPostItemProps): React.

const defaultCover = 'https://github.com/asyncapi/community/assets/40604284/01c2b8de-fa5c-44dd-81a5-70cb96df4813';
let active = true;
const postDate = moment(post.date); // Convert post.date to a moment object if necessary

if (!postDate.isValid()) {
// Handle invalid date if necessary
active = false;
} else if (currentDate > postDate.format()) {
let postDate: Date = new Date();

try {
postDate = parseDate(post.date);
if (isDateBefore(postDate, currentDate)) {
active = false;
}
} catch {
active = false;
}

Expand All @@ -80,7 +81,7 @@ function EventPostItem({ post, className = '', id }: EventPostItemProps): React.
<div className='flex items-center'>
<IconCalendar />
<span className='ml-4 text-sm font-semibold' data-testid='Event-span'>
{active ? moment(postDate).format('MMMM D, YYYY') : 'View Recording'}
{active ? formatDate(postDate, 'MMMM d, yyyy') : 'View Recording'}
</span>
<ArrowRightIcon className='ml-3 w-4' />
</div>
Expand Down
4 changes: 2 additions & 2 deletions components/newsroom/FeaturedBlogPost.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import moment from 'moment';
import Link from 'next/link';
import React from 'react';
import TextTruncate from 'react-text-truncate';

import { BlogPostType } from '@/types/components/navigation/BlogPostType';
import { formatDate } from '@/utils/dateHelpers';
import type { IBlogPost } from '@/types/post';
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';
Expand Down Expand Up @@ -100,7 +100,7 @@ export default function FeaturedBlogPost({ post, className = '' }: FeaturedBlogP
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.sm} className='flex'>
<time dateTime={post.date} data-testid='FeaturedBlogPost-date'>
{moment(post.date).format('MMMM D, YYYY')}
{formatDate(post.date, 'MMMM d, yyyy')}
</time>
<span className='mx-1'>&middot;</span>
<span data-testid='FeaturedBlogPost-RT'>{post.readingTime} min read</span>
Expand Down
4 changes: 2 additions & 2 deletions config/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@
"borderColor": "border-[#CA1A33]"
},
{
"name": "Liquid",
"name": "AsyncAPI CLI",
"color": "bg-[#61d0f2]",
"borderColor": "border-[#40ccf7]"
},
Expand Down Expand Up @@ -1556,7 +1556,7 @@
"borderColor": "border-[#CA1A33]"
},
{
"name": "Liquid",
"name": "AsyncAPI CLI",
"color": "bg-[#61d0f2]",
"borderColor": "border-[#40ccf7]"
},
Expand Down
21 changes: 11 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"axios": "^1.12.1",
"clsx": "^2.1.0",
"cssnano": "^6.0.3",
"date-fns": "^4.1.0",
"dedent": "^1.5.1",
"dotenv": "^16.4.4",
"fs-extra": "^11.2.0",
Expand All @@ -89,7 +90,6 @@
"markdown-toc": "^1.2.0",
"md5": "^2.3.0",
"mermaid": "9.3.0",
"moment": "^2.30.1",
"next": "15.5.9",
"next-i18next": "^15.3.0",
"next-language-detector": "^1.1.1",
Expand Down
9 changes: 4 additions & 5 deletions pages/community/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type moment from 'moment';
import React from 'react';

import { CardType } from '@/types/components/community/CardPropsType';
Expand All @@ -12,11 +11,12 @@ import GenericLayout from '../../components/layout/GenericLayout';
import NewsletterSubscribe from '../../components/NewsletterSubscribe';
import Heading from '../../components/typography/Heading';
import eventsData from '../../config/meetings.json';
import { formatDate, formatDateWithTimezone } from '../../utils/dateHelpers';
import { getEvents } from '../../utils/staticHelpers';

interface Event {
title: string;
date: moment.Moment;
date: Date;
url: string;
}

Expand Down Expand Up @@ -127,13 +127,12 @@ export default function CommunityIndexPage() {
<li key={index} className='mt-2 w-full rounded-l-md bg-white p-2 md:p-10'>
<a href={event.url} className='flex'>
<div className='inline-flex h-12 min-w-12 flex-row rounded-full bg-pink-500 font-bold text-white'>
<span className='flex-1 self-center text-center'>{event.date.format('D')}</span>
<span className='flex-1 self-center text-center'>{formatDate(event.date, 'd')}</span>
</div>
<div className='ml-4 text-left'>
<h1 className='text-md md:text-lg'>{event.title}</h1>
<span className='text-xs text-gray-500 md:text-sm'>
{event.date.local().format('LLLL')} UTC
{event.date.local().format('Z')}
{formatDateWithTimezone(event.date)}
</span>
</div>
</a>
Expand Down
4 changes: 2 additions & 2 deletions scripts/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
*/

import dedent from 'dedent';
import { format } from 'date-fns';
import fs from 'fs';
import inquirer from 'inquirer';
import moment from 'moment';

import { logger } from './helpers/logger';

Expand Down Expand Up @@ -41,7 +41,7 @@ function genFrontMatter(answers: ComposePromptType): string {

let frontMatter = dedent`---
title: ${answers.title ? answers.title : 'Untitled'}
date: ${moment().format('YYYY-MM-DDTh:mm:ssZ')}
date: ${format(new Date(), "yyyy-MM-dd'T'HH:mm:ssXXX")}
type: ${answers.type}
canonical: ${answers.canonical ? answers.canonical : ''}
tags: [${answers.tags ? tags : ''}]
Expand Down
Loading
Loading