-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/r d page #51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/r d page #51
Conversation
WalkthroughThis pull request introduces a comprehensive set of React components and GraphQL queries for a Research and Development (R&D) page. The changes include creating multiple components for displaying hero sections, tab contents, publications, research areas, fellows, and testimonials. A new custom hook Changes
Sequence DiagramsequenceDiagram
participant Page as R&D Page
participant Hero as Hero Component
participant TabSection as Tab Section
participant GraphQL as GraphQL Query
Page->>GraphQL: Fetch hero and tabs data
GraphQL-->>Page: Return data
Page->>Hero: Render with heroData
Page->>TabSection: Render with tabsData
TabSection->>TabSection: Manage active tab
TabSection->>FellowshipContent/ResearchContent: Render based on active tab
Possibly related PRs
Suggested reviewers
Poem
Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
✅ Deploy Preview for kleros-website-v2 canceled.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
🧹 Nitpick comments (26)
frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Testimonials/TestimonialCard.tsx (1)
8-8
: Consider maintaining aspect ratio using padding-top technique.The current fixed height approach might cause layout shifts. Consider using padding-top technique to maintain aspect ratio.
- <div className="relative h-[203px] w-full overflow-hidden rounded-2xl"> + <div className="relative w-full overflow-hidden rounded-2xl" style={{ paddingTop: '56.25%' }}>frontend/src/queries/research-development/hero.ts (1)
29-39
: Add error handling and URL validation to type definition.Consider enhancing the type safety:
- Make fields optional to handle partial data
- Add URL format validation
- Add JSDoc documentation
+/** + * Type definition for the hero section query response + * @property rAndDPageHero - Hero section data + */ export type HeroQueryType = { rAndDPageHero: { - header: string; - subtitle: string; - buttons: ArrowLink[]; - arrowLink: ArrowLink[]; + header?: string; + subtitle?: string; + buttons?: ArrowLink[]; + arrowLink?: ArrowLink[]; background: { - url: string; + url: `https://${string}` | `http://${string}`; // URL format validation }; }; };frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/index.tsx (1)
16-23
: Add error boundary and loading states.Consider implementing error boundaries and loading states for better user experience.
+import { Suspense } from 'react'; +import ErrorBoundary from '@/components/ErrorBoundary'; +import LoadingSpinner from '@/components/LoadingSpinner'; const ResearchTabContent: React.FC<IResearchTabContent> = (props) => { return ( <div> + <ErrorBoundary fallback={<div>Error loading content</div>}> + <Suspense fallback={<LoadingSpinner />}> <ResearchSection {...props} /> <PublicationSection {...props} /> + </Suspense> + </ErrorBoundary> </div> ); };frontend/src/app/r-and-d/page.tsx (1)
10-19
: Add metadata for SEO optimization.Consider adding metadata for better SEO optimization.
+export const metadata = { + title: 'Research & Development | Your Company', + description: 'Explore our research and development initiatives...', + openGraph: { + title: 'Research & Development | Your Company', + description: 'Explore our research and development initiatives...', + } +}; const ResearchDevelopment: React.FC = async () => {frontend/src/hooks/useScreenSize.tsx (2)
10-25
: Add debouncing to resize event handlerThe resize event handler could fire frequently during window resizing, potentially impacting performance. Consider debouncing the handler.
+ import { debounce } from "lodash"; + useEffect(() => { - const handleResize = () => { + const handleResize = debounce(() => { if (window.innerWidth < 768) { setScreenSize("sm"); } else if (window.innerWidth >= 768 && window.innerWidth < 1024) { setScreenSize("md"); } else if (window.innerWidth >= 1024) { setScreenSize("lg"); } - }; + }, 250); window.addEventListener("resize", handleResize); handleResize(); return () => { + handleResize.cancel(); window.removeEventListener("resize", handleResize); }; }, []);
12-18
: Extract breakpoint values to constantsMagic numbers for breakpoints should be centralized in a configuration file for better maintainability.
+ const BREAKPOINTS = { + SM: 768, + MD: 1024, + } as const; + - if (window.innerWidth < 768) { + if (window.innerWidth < BREAKPOINTS.SM) { setScreenSize("sm"); - } else if (window.innerWidth >= 768 && window.innerWidth < 1024) { + } else if (window.innerWidth >= BREAKPOINTS.SM && window.innerWidth < BREAKPOINTS.MD) { setScreenSize("md"); - } else if (window.innerWidth >= 1024) { + } else if (window.innerWidth >= BREAKPOINTS.MD) { setScreenSize("lg"); }frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/ResearchSection/ResearchCard.tsx (1)
9-14
: Extract complex className into a constantLong className strings should be extracted for better maintainability.
+ const cardClassName = clsx( + "relative min-h-[185px] w-full", + "rounded-2xl border border-stroke bg-background-2", + "before:absolute before:left-[-1px] before:top-1/2 before:h-[146px] before:-translate-y-1/2 before:border-r-2 before:border-primary-purple", + "flex items-center justify-start gap-4 p-6", + ); + <div - className={clsx( - "relative min-h-[185px] w-full", - "rounded-2xl border border-stroke bg-background-2", - "before:absolute before:left-[-1px] before:top-1/2 before:h-[146px] before:-translate-y-1/2 before:border-r-2 before:border-primary-purple", - "flex items-center justify-start gap-4 p-6", - )} + className={cardClassName} >frontend/src/components/Pagination.tsx (1)
17-17
: Add descriptive aria-label to pagination containerThe pagination container should have a descriptive label for screen readers.
- <div className={clsx("flex items-center gap-8", className)}> + <div + role="navigation" + aria-label="Pagination" + className={clsx("flex items-center gap-8", className)} + >frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/index.tsx (2)
23-36
: Improve semantic structure and accessibilityThe component's HTML structure could be more semantic and accessible.
- <div className="flex flex-col gap-8 pb-12 pt-[88px] lg:py-24"> + <section + className="flex flex-col gap-8 pb-12 pt-[88px] lg:py-24" + aria-labelledby="fellowship-header" + > - <h1 className="text-2xl font-medium text-primary-text md:text-3xl"> + <h1 + id="fellowship-header" + className="text-2xl font-medium text-primary-text md:text-3xl" + > {header} </h1> <p className="text-lg text-secondary-text">{subtitle}</p> - <h3 className="my-8 text-xl text-secondary-text">{testimonialsHeader}</h3> + <h2 className="my-8 text-xl text-secondary-text">{testimonialsHeader}</h2> <Testimonials testimonials={testimonials} /> - <h3 className="my-4 text-xl text-secondary-text">{fellowsHeader}</h3> + <h2 className="my-4 text-xl text-secondary-text">{fellowsHeader}</h2> <Fellows fellows={fellows} /> - </div> + </section>
15-37
: Consider memoizing the component for performanceIf this component is used in a context where its parent frequently re-renders, consider memoizing it.
- const FellowshipTabContent: React.FC<IFellowshipTabContent> = ({ + const FellowshipTabContent: React.FC<IFellowshipTabContent> = React.memo(({ header, subtitle, testimonialsHeader, fellowsHeader, testimonials, fellows, - }) => { + }) => { return ( // ... component JSX ); - }; + });frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Fellows/FellowCard.tsx (1)
26-28
: Replace label with more semantic heading elementUsing
label
for displaying profession is semantically incorrect as it's not associated with any form control.-<label className="mb-6 font-medium text-secondary-text"> +<h3 className="mb-6 font-medium text-secondary-text"> {profession} -</label> +</h3>frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Fellows/index.tsx (2)
14-17
: Consider using CSS media queries instead of JS for responsive designUsing JavaScript to determine screen size for layout purposes can cause unnecessary re-renders and potential layout shifts. Consider using CSS Grid or Flexbox with media queries instead.
-const itemsPerPage = useMemo( - () => (screenSize === "sm" ? 1 : 2), - [screenSize], -); +const itemsPerPage = 2;Then update the grid to handle responsiveness with CSS:
-<div className="mb-12 grid grid-cols-1 gap-4 lg:grid-cols-2"> +<div className="mb-12 grid grid-cols-1 gap-4 sm:grid-cols-2">
31-33
: Add proper TypeScript key type and improve accessibility
- Using name as a key might lead to issues if there are fellows with the same name
- The grid items should have proper ARIA roles for better accessibility
-{items.map((fellow) => ( - <FellowCard key={fellow.name} {...fellow} /> -))} +{items.map((fellow, index) => ( + <div key={`${fellow.name}-${index}`} role="article"> + <FellowCard {...fellow} /> + </div> +))}frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/ResearchSection/index.tsx (2)
27-33
: Improve semantic structure and accessibilityThe heading hierarchy and semantic structure need improvements:
- Consider using
section
witharia-labelledby
- Ensure proper heading hierarchy
-<div className="flex flex-col gap-8 pb-12 pt-[88px] lg:py-24"> +<section + className="flex flex-col gap-8 pb-12 pt-[88px] lg:py-24" + aria-labelledby="research-header" +> - <h1 className="text-2xl font-medium text-primary-text md:text-3xl"> + <h2 id="research-header" className="text-2xl font-medium text-primary-text md:text-3xl"> {researchHeader} - </h1> + </h2> <h3 className="text-xl text-secondary-text">{researchSecondaryHeader}</h3> <p className="text-lg text-secondary-text">{researchParagraph}</p> - <label className="text-lg text-secondary-text">{researchCardLabel}</label> + <p className="text-lg text-secondary-text">{researchCardLabel}</p>
34-38
: Add proper ARIA roles and improve grid accessibilityThe grid of research cards needs proper ARIA roles and landmarks for better accessibility.
-<div className="mt-8 grid grid-cols-1 gap-4 md:grid-cols-2"> +<div + className="mt-8 grid grid-cols-1 gap-4 md:grid-cols-2" + role="list" +> {researches.map((research) => ( - <ResearchCard key={research.field} {...research} /> + <div key={research.field} role="listitem"> + <ResearchCard {...research} /> + </div> ))} </div>frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Testimonials/index.tsx (1)
33-35
: Avoid using array index in key prop when possible.Using a combination of URL and array index as key might cause issues if testimonials are reordered. Consider using a unique identifier from the testimonial data if available.
- <TestimonialCard key={`${testimonial.url}-${i}`} {...testimonial} /> + <TestimonialCard key={testimonial.url} {...testimonial} />frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/TeamPublications.tsx (2)
34-34
: Simplify prop spreading syntax.The current prop spreading syntax is unnecessarily verbose.
- <PublicationCard key={publication.topic} {...{ publication }} /> + <PublicationCard key={publication.topic} publication={publication} />
1-47
: Consider creating a reusable pagination component.This component shares significant logic with the Testimonials component. Consider creating a generic paginated list component to reduce code duplication.
You could create a reusable component like:
interface PaginatedListProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; itemsPerPage?: number; className?: string; } function PaginatedList<T>({ items, renderItem, itemsPerPage = 3, className }: PaginatedListProps<T>) { // Shared pagination logic here }Would you like me to help create this reusable component?
frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/index.tsx (1)
30-32
: Review heading hierarchy.Using h1 for a section heading might not be appropriate if this isn't the main heading of the page. Consider using h2 instead to maintain proper document outline.
- <h1 className="mb-8 text-2xl text-primary-text lg:text-3xl lg:font-medium"> + <h2 className="mb-8 text-2xl text-primary-text lg:text-3xl lg:font-medium"> {publicationsHeader} - </h1> + </h2>frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/WaitlistSection.tsx (1)
28-36
: Add aria-label to improve accessibility.The link to apply could benefit from a more descriptive aria-label for better accessibility.
<Link href={applyButton.link.url} target="_blank" rel="noreferrer noopener" + aria-label={`Apply for ${header}`} >
frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/ThirdPartyPublications.tsx (1)
37-42
: Enhance pagination accessibilityThe Pagination component should have proper ARIA labels for better screen reader support.
<Pagination currentPage={page} numPages={Math.ceil(thirdPartyPublications.length / itemsPerPage)} callback={(val) => setPage(val)} className="w-full justify-center" + aria-label="Publications navigation" />
frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/KlerosBook.tsx (1)
30-41
: Add loading state for download buttonsConsider adding a loading state to the Button component when downloads are initiated.
<div className="flex flex-wrap gap-4"> {downloadFormats.map((format) => ( <Link key={format.text} href={format.link.url} target="_blank" rel="noreferrer noopener" + onClick={(e) => { + const button = e.currentTarget.querySelector('button'); + if (button) button.classList.add('loading'); + }} > <Button className="text-background-1">{format.text}</Button> </Link> ))} </div>frontend/src/components/ResearchDevelopment/TabSection/index.tsx (1)
31-37
: Add ARIA labels for tab navigationEnhance accessibility by adding proper ARIA labels to the Tab component.
<Tab items={tabItems} currentValue={activeTab} callback={(val: number) => { setActiveTab(val); }} + aria-label="Research and Development sections" />
frontend/src/components/ResearchDevelopment/Hero.tsx (1)
26-37
: Enhance link security attributesAdd additional security attributes to external links to prevent potential security vulnerabilities.
{buttons.map((button) => ( <Link key={button.text} href={button.link.url} target="_blank" - rel="noopener noreferrer" + rel="noopener noreferrer nofollow" + referrerPolicy="no-referrer" > <Button variant="secondary"> <span>{button.text}</span> </Button> </Link> ))}frontend/src/queries/research-development/tabs-data.ts (2)
113-117
: Consider making fields optional where appropriate.The
TeamPublication
andThirdPartyPublication
types assume all fields are required. Consider making some fields optional using the?
operator for better flexibility and error handling.export type TeamPublication = { topic: string; - authors: string; + authors?: string; paperLink: ArrowLink; }; export type ThirdPartyPublication = { topic: string; - paperLink: ArrowLink; + paperLink?: ArrowLink; };Also applies to: 119-122
179-187
: Add JSDoc comments for better documentation.The
TabSectionQueryType
is a crucial type that represents the entire query response. Consider adding JSDoc comments to improve documentation and maintainability.+/** + * Represents the complete response structure for the R&D page tab section query + * @property rAndDPageResearchTabSection - Research tab section data + * @property rAndDPageFellowshipTabSection - Fellowship tab section data + * @property researches - Array of research areas + * @property teamPublications - Array of team publications + * @property thirdPartyPublications - Array of third-party publications + * @property testimonials - Array of testimonials + * @property fellows - Array of fellows + */ export type TabSectionQueryType = { rAndDPageResearchTabSection: RAndDPageResearchTabSection; rAndDPageFellowshipTabSection: RAndDPageFellowshipTabSection; researches: Research[]; teamPublications: TeamPublication[]; thirdPartyPublications: ThirdPartyPublication[]; testimonials: Testimonial[]; fellows: Fellow[]; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
frontend/src/app/r-and-d/page.tsx
(1 hunks)frontend/src/components/Earn/TabSection/CuratorTabContent/KlerosScoutSection.tsx
(1 hunks)frontend/src/components/Pagination.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/Hero.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Fellows/FellowCard.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Fellows/index.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Testimonials/TestimonialCard.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/Testimonials/index.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/WaitlistSection.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/FellowshipTabContent/index.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/KlerosBook.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/PublicationCard.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/TeamPublications.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/ThirdPartyPublications.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/PublicationsSection/index.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/ResearchSection/ResearchCard.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/ResearchSection/index.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/index.tsx
(1 hunks)frontend/src/components/ResearchDevelopment/TabSection/index.tsx
(1 hunks)frontend/src/hooks/useScreenSize.tsx
(1 hunks)frontend/src/queries/research-development/hero.ts
(1 hunks)frontend/src/queries/research-development/tabs-data.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- frontend/src/components/Earn/TabSection/CuratorTabContent/KlerosScoutSection.tsx
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Redirect rules - kleros-website-v2
- GitHub Check: Header rules - kleros-website-v2
- GitHub Check: Pages changed - kleros-website-v2
🔇 Additional comments (3)
frontend/src/queries/research-development/tabs-data.ts (3)
60-65
: Review pagination strategy and consider implementing cursor-based pagination.The current implementation uses limit-based pagination with a fixed limit of 50 items for multiple collections. Consider the following recommendations:
- Implement cursor-based pagination for better scalability
- Add proper error handling for cases where data exceeds the limit
- Consider implementing lazy loading for better performance
Let's verify the current data volume:
Also applies to: 67-76, 78-86, 88-93, 95-104
3-3
: Verify ArrowLink type compatibility.The
ArrowLink
type is imported from the navbar module and used in multiple places. Let's ensure its structure matches the expected usage in this context.Also applies to: 116-116, 121-121, 143-143, 163-164
✅ Verification successful
ArrowLink type is correctly structured and used.
The
ArrowLink
type from navbar module is properly defined withtext
andlink
fields, matching its usage in the GraphQL query responses and type definitions throughout tabs-data.ts.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check ArrowLink type definition and usage rg -g '!node_modules' -g '*.{ts,tsx}' 'export.*ArrowLink.*='Length of output: 120
Script:
#!/bin/bash # Get the ArrowLink type definition with context rg -g '!node_modules' -g '*.{ts,tsx}' -B 2 -A 5 'export type ArrowLink = {' # Find ArrowLink usage in tabs-data.ts cat frontend/src/queries/research-development/tabs-data.tsLength of output: 3534
Script:
#!/bin/bash # Get the ArrowLink type definition with escaped curly braces rg -g '!node_modules' -g '*.{ts,tsx}' -B 2 -A 5 'export type ArrowLink = \{'Length of output: 430
24-26
: Implement URL validation and security measures.The query includes multiple URL fields that could potentially expose sensitive information or be vulnerable to manipulation. Consider:
- Implementing URL validation
- Adding URL sanitization
- Using relative URLs where possible
- Implementing URL access control if needed
Let's check for any existing URL validation:
Also applies to: 44-46, 49-52, 62-64, 71-74, 80-84, 89-92, 100-103
...ponents/ResearchDevelopment/TabSection/FellowshipTabContent/Testimonials/TestimonialCard.tsx
Show resolved
Hide resolved
frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/index.tsx
Show resolved
Hide resolved
...omponents/ResearchDevelopment/TabSection/ResearchTabContent/ResearchSection/ResearchCard.tsx
Show resolved
Hide resolved
...archDevelopment/TabSection/ResearchTabContent/PublicationsSection/ThirdPartyPublications.tsx
Show resolved
Hide resolved
frontend/src/components/ResearchDevelopment/TabSection/ResearchTabContent/KlerosBook.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Summary by CodeRabbit
Release Notes
New Features
Components Added
Enhancements