Skip to content
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

Feature/speaker profile bio #258

Merged

Conversation

christopher-adolphe
Copy link
Contributor

@christopher-adolphe christopher-adolphe commented Dec 3, 2024

  • Add speakers-profile.json file
  • Update getSpeaker() function to get speaker's profile data
  • Update markup in SpeakerSingle component to display speaker's profile details
  • Add middleware to Speaker page to enhance error handling for non-existing speaker ID

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new JSON file containing detailed speaker profiles.
    • Added a user-friendly error component for handling page not found scenarios.
    • Enhanced speaker retrieval with improved error handling and flexible data access.
  • Improvements

    • Restructured the speaker component for better type safety and readability.
    • Updated interfaces to capture more comprehensive speaker information.
  • Bug Fixes

    • Implemented checks for speaker existence to prevent navigation errors.

Copy link
Contributor

coderabbitai bot commented Dec 3, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

The changes introduced in this pull request involve the addition of a new JSON file for speaker profiles, significant updates to the Single.vue component for improved type safety and readability, the creation of a new error handling component, and modifications to the speaker page to enhance error handling and data retrieval. Additionally, updates to TypeScript interfaces in the utility types file expand the data model for speakers, allowing for richer data representation.

Changes

File Path Change Summary
packages/frontendmu-data/data/speakers-profile.json New JSON file added containing an array of speaker profiles with fields such as bio, job_title, location, website, github, and twitter.
packages/frontendmu-nuxt/components/speaker/Single.vue Restructured component with updated props using SpeakerSingleProps interface, added computed properties for better data access, enhanced template readability, and adjusted layout and CSS for responsiveness.
packages/frontendmu-nuxt/error.vue New Vue component created for handling error messages, utilizing <script setup> syntax with TypeScript, and including a user-friendly error message layout with a navigation button back to the homepage.
packages/frontendmu-nuxt/pages/speaker/[id].vue Middleware added for 404 error handling based on speaker existence, modified getSpeaker function signature for flexibility, and streamlined template usage by directly passing the speaker object to the SpeakerSingle component.
packages/frontendmu-nuxt/utils/types.ts Updated Speaker interface with new properties (status, sort, featured, date_created, date_updated) and added a new SpeakerProfile interface for detailed speaker representation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SpeakerPage
    participant SpeakerData
    participant ErrorComponent

    User->>SpeakerPage: Request speaker profile
    SpeakerPage->>SpeakerData: Fetch speaker data
    alt Speaker exists
        SpeakerData-->>SpeakerPage: Return speaker profile
        SpeakerPage->>User: Display speaker profile
    else Speaker does not exist
        SpeakerPage->>ErrorComponent: Trigger error handling
        ErrorComponent-->>User: Display 404 error message
    end
Loading

🐰 "In the land of code, where speakers thrive,
New profiles emerge, keeping data alive.
With errors caught and props refined,
A clearer path for all to find.
Hops of joy in every line,
In this code, our dreams align!" 🐇


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 77a998d and 38c0dad.

📒 Files selected for processing (1)
  • packages/frontendmu-data/data/speakers-profile.json (1 hunks)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (7)
packages/frontendmu-nuxt/error.vue (1)

25-30: Enhance button accessibility

The button element should have proper ARIA attributes for better accessibility.

 <button
   class="mx-auto bg-verse-500 hover:bg-verse-600 transition-colors duration-200 text-md block rounded-full px-4 py-4 text-center font-medium text-white md:px-6 md:text-lg cursor-pointer"
+  aria-label="Return to homepage"
+  role="button"
   @click="handleError"
 >
   Back to Home
 </button>
packages/frontendmu-nuxt/pages/speaker/[id].vue (3)

Line range hint 26-48: Improve type safety and error handling in getSpeaker

The function needs better typing and error handling.

-function getSpeaker(id: string | string[]) {
+interface Speaker {
+  id: string;
+  name: string;
+  github_account: string;
+}

+interface SpeakerSession {
+  Session_id: {
+    speakers: {
+      id: string;
+    };
+  };
+}

+interface SpeakerData {
+  person: Speaker;
+  sessions: SpeakerSession[];
+  profile: typeof speakersProfileResponse[0];
+  Date: string;
+  Venue: string;
+}

+function getSpeaker(id: string | string[]): SpeakerData | undefined {
-  const speaker = speakersResponse.find((ev: { id: string }) => String(ev.id) === String(id))
+  const speaker = findSpeakerById(id)

51-51: Consider memoizing speaker data and add error boundaries

The speaker data computation and head metadata could be optimized.

-const speaker = ref(getSpeaker(route.params.id))
+const speaker = computed(() => getSpeaker(route.params.id))

+const speakerName = computed(() => speaker.value?.person?.name ?? 'Speaker Not Found')

 useHead({
-  title: speaker.value?.person ? speaker.value.person.name : '',
+  title: speakerName.value,
   meta: [
     {
       hid: 'description',
       name: 'description',
-      content: 'frontend.mu speaker profile',
+      content: `frontend.mu profile for ${speakerName.value}`,
     },
   ],
 })

Also applies to: 54-66


72-74: Add loading and error states to the template

The template should handle loading and error states explicitly.

 <div>
+  <template v-if="pending">
+    <LoadingSpinner />
+  </template>
   <template v-if="speaker">
     <SpeakerSingle :speaker="speaker" />
   </template>
+  <template v-else-if="!pending">
+    <ErrorMessage message="Speaker data could not be loaded" />
+  </template>
 </div>
packages/frontendmu-nuxt/utils/types.ts (1)

262-268: Consider enhancing type safety for the Speaker interface

The interface could benefit from stronger type constraints:

  • status could use a string literal union type to restrict possible values
  • sort being nullable might lead to inconsistent sorting behavior

Consider this improvement:

-  status: string
-  sort: string | null
+  status: 'active' | 'inactive' | 'pending'  // adjust values based on business logic
+  sort: number | null  // if this represents order/position
packages/frontendmu-nuxt/components/speaker/Single.vue (2)

9-28: Consider optimizing profile-related computed properties

The multiple computed properties for profile checks could be consolidated into a single computed property for better maintainability.

Consider this improvement:

-const hasProfileLocation = computed(() => profile.value.location !== '')
-const hasProfileWebsite = computed(() => profile.value.website !== '')
-const hasProfileGithub = computed(() => profile.value.github !== '')
-const hasProfileTwitter = computed(() => profile.value.twitter !== '')
+const profileLinks = computed(() => ({
+  hasLocation: profile.value.location !== '',
+  hasWebsite: profile.value.website !== '',
+  hasGithub: profile.value.github !== '',
+  hasTwitter: profile.value.twitter !== ''
+}))

Line range hint 35-138: Consider adding error boundary and loading states

The component could benefit from proper error handling and loading states to improve user experience.

Consider wrapping the component with an error boundary and adding loading states:

<template>
  <ErrorBoundary v-slot="{ error }">
    <div v-if="error">
      <!-- Error state UI -->
    </div>
    <div v-else-if="isLoading">
      <!-- Loading state UI -->
    </div>
    <div v-else>
      <!-- Existing component content -->
    </div>
  </ErrorBoundary>
</template>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 260719d and 9c6b6a8.

📒 Files selected for processing (5)
  • packages/frontendmu-data/data/speakers-profile.json (1 hunks)
  • packages/frontendmu-nuxt/components/speaker/Single.vue (2 hunks)
  • packages/frontendmu-nuxt/error.vue (1 hunks)
  • packages/frontendmu-nuxt/pages/speaker/[id].vue (3 hunks)
  • packages/frontendmu-nuxt/utils/types.ts (2 hunks)
🔇 Additional comments (1)
packages/frontendmu-data/data/speakers-profile.json (1)

1-38: Consider data completeness and validation

The speaker profiles data structure has several areas for improvement:

  1. Most profiles (3 out of 4) have empty fields which might affect the UI display
  2. Twitter handle format is inconsistent (e.g., "@sun" vs empty string)
  3. No schema validation is apparent for the data structure

Consider implementing the following improvements:

  1. Add JSON schema validation to ensure data consistency
  2. Define default values for empty fields
  3. Standardize social media handle formats (with or without @ prefix)
  4. Document the required vs optional fields

Let's verify the data usage in the frontend:

✅ Verification successful

Empty fields are handled gracefully in the UI

After examining the codebase, I can verify that:

  1. Empty fields are properly handled with conditional rendering (v-if) in the Single.vue component:
    • Location, website, GitHub, and Twitter links only appear when their respective values are non-empty
    • Computed properties (hasProfileLocation, hasProfileWebsite, etc.) check for empty strings
  2. The data structure is consistently used across components
  3. Twitter handle format inconsistency doesn't affect the UI as the handle is used correctly in the Twitter URL construction
  4. The profile data is properly typed with TypeScript interfaces

While schema validation could still be beneficial for data integrity, the current implementation safely handles incomplete profile data.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how empty fields are handled in the UI
rg -l "speaker\.(website|twitter|github|bio|job_title)" packages/frontendmu-nuxt/

Length of output: 83


Script:

#!/bin/bash
# Let's try a broader search to find where speaker data is used
rg -l "speakers-profile" 

# Also search for any component or page that might render speaker information
rg -l "speaker" --type vue --type js

# Check if there's any schema validation file
fd "schema" --extension json --extension js

Length of output: 181


Script:

#!/bin/bash
# Let's examine how the speaker data is used in the page component
cat "packages/frontendmu-nuxt/pages/speaker/[id].vue"

# Let's also check if there are any Vue files with 'speaker' in their name or content using ripgrep
rg -l "speaker" --glob "*.vue"

Length of output: 2499


Script:

#!/bin/bash
# Let's check how the speaker data is rendered in the Single component
cat "packages/frontendmu-nuxt/components/speaker/Single.vue"

# Also check the List component to see how multiple speakers are displayed
cat "packages/frontendmu-nuxt/components/speaker/List.vue"

Length of output: 6069

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
packages/frontendmu-nuxt/utils/types.ts (2)

262-268: Consider improving type safety for status and dates

The interface could benefit from these improvements:

  • Define an enum or union type for status to restrict possible values
  • Consider using Date type for date fields to ensure proper date handling
+export type SpeakerStatus = 'active' | 'inactive' | 'pending'

 export interface Speaker {
   id: string
-  status: string
+  status: SpeakerStatus
   sort: string | null
   name: string
   github_account: string
   featured: boolean
-  date_created: string
-  date_updated: string
+  date_created: Date
+  date_updated: Date
 }

288-294: Consider optional fields and date validation

The interface could benefit from these improvements:

  • Make event-related fields optional
  • Add date format validation
 export interface SpeakerProfileWithSessions {
   person: Speaker
   sessions: Sponsor[]
   profile: SpeakerProfile
-  Date: string
-  Venue: string
+  Date?: string  // Consider using ISO date format
+  Venue?: string
 }
packages/frontendmu-nuxt/components/speaker/Single.vue (1)

9-23: Improve validation for optional profile fields

The current empty string checks might not be the best way to validate optional fields. Consider using optional chaining and nullish coalescing for better handling.

 const profile = computed(() => props.speaker.profile)
-const hasProfileBio = computed(() => profile.value.bio !== '')
-const hasProfileLocation = computed(() => profile.value.location !== '')
-const hasProfileWebsite = computed(() => profile.value.website !== '')
-const hasProfileGithub = computed(() => profile.value.github !== '')
-const hasProfileTwitter = computed(() => profile.value.twitter !== '')
+const hasProfileBio = computed(() => !!profile.value?.bio)
+const hasProfileLocation = computed(() => !!profile.value?.location)
+const hasProfileWebsite = computed(() => !!profile.value?.website)
+const hasProfileGithub = computed(() => !!profile.value?.github)
+const hasProfileTwitter = computed(() => !!profile.value?.twitter)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9c6b6a8 and d3cfe60.

📒 Files selected for processing (4)
  • packages/frontendmu-data/data/speakers-profile.json (1 hunks)
  • packages/frontendmu-nuxt/components/speaker/Single.vue (2 hunks)
  • packages/frontendmu-nuxt/pages/speaker/[id].vue (3 hunks)
  • packages/frontendmu-nuxt/utils/types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/frontendmu-data/data/speakers-profile.json
  • packages/frontendmu-nuxt/pages/speaker/[id].vue
🔇 Additional comments (3)
packages/frontendmu-nuxt/utils/types.ts (1)

278-286: 🛠️ Refactor suggestion

Make social fields optional and add validation

The interface could benefit from these improvements:

  • Make social media fields optional as not all speakers might have them
  • Add URL validation for website field
  • Add constraints for text fields
+type ValidUrl = `https://${string}` | `http://${string}`

 export interface SpeakerProfile {
   id: string
-  bio: string
+  bio: string  // Consider maxLength validation
   job_title: string
   location: string
-  website: string
-  github: string
-  twitter: string
+  website?: ValidUrl
+  github?: string  // Consider pattern validation ^[a-zA-Z0-9-]+$
+  twitter?: string  // Consider pattern validation ^[a-zA-Z0-9_]+$
 }

Likely invalid or redundant comment.

packages/frontendmu-nuxt/components/speaker/Single.vue (2)

74-78: Consider improving image handling

The current implementation could benefit from fallback image handling, loading state, and image optimization.


101-123: Add security attributes to external links

External links should include security attributes to prevent potential security issues.

#!/bin/bash
# Description: Check for external links without security attributes
# Test: Search for NuxtLink components with target="_blank" but missing rel="noopener noreferrer"

ast-grep --pattern 'NuxtLink[
  @target="_blank"
  !@rel="noopener noreferrer"
]'

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
packages/frontendmu-nuxt/components/speaker/Single.vue (2)

18-23: Consider improving profile attribute validation

The current empty string checks could be enhanced to handle undefined values and whitespace-only strings.

Consider this more robust implementation:

-const hasProfileBio = computed(() => profile.value.bio !== '')
-const hasProfileLocation = computed(() => profile.value.location !== '')
-const hasProfileWebsite = computed(() => profile.value.website !== '')
-const hasProfileGithub = computed(() => profile.value.github !== '')
-const hasProfileTwitter = computed(() => profile.value.twitter !== '')
+const hasProfileBio = computed(() => !!profile.value?.bio?.trim())
+const hasProfileLocation = computed(() => !!profile.value?.location?.trim())
+const hasProfileWebsite = computed(() => !!profile.value?.website?.trim())
+const hasProfileGithub = computed(() => !!profile.value?.github?.trim())
+const hasProfileTwitter = computed(() => !!profile.value?.twitter?.trim())

80-83: Consider using CSS custom properties for z-index management

The z-index values (z-10, z-20) could be managed more effectively using CSS custom properties.

Consider defining z-index values at the component root:

+<style scoped>
+:root {
+  --z-background: 10;
+  --z-content: 20;
+}
+</style>

-class="... z-20 ..."
+class="..." style="z-index: var(--z-content)"

-class="... z-10"
+class="..." style="z-index: var(--z-background)"

Also applies to: 127-129

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d3cfe60 and 77a998d.

📒 Files selected for processing (1)
  • packages/frontendmu-nuxt/components/speaker/Single.vue (2 hunks)
🔇 Additional comments (3)
packages/frontendmu-nuxt/components/speaker/Single.vue (3)

7-13: LGTM! Good type safety improvements

The transition to TypeScript generics for props definition and the introduction of a proper interface improves type safety and maintainability.


74-78: Consider improving image handling

The current implementation could benefit from image optimization and fallback handling, as noted in the previous review.


96-124: 🛠️ Refactor suggestion

Enhance accessibility for social links

The social links navigation could benefit from improved accessibility.

Consider these improvements:

-<nav class="grid gap-2 *:flex *:justify-start *:items-center *:gap-2">
+<nav class="grid gap-2 *:flex *:justify-start *:items-center *:gap-2" aria-label="Social links">
   <span v-if="hasProfileLocation">
-    <Icon name="lucide:map-pin" mode="svg" class="size-6" />{{ profile.location }}
+    <Icon name="lucide:map-pin" mode="svg" class="size-6" aria-label="Location" />
+    <span>{{ profile.location }}</span>
   </span>

   <NuxtLink
     v-if="hasProfileWebsite"
     :to="profile.website"
     target="_blank"
+    :aria-label="`Visit ${person.name}'s website`"
   >
-    <Icon name="lucide:link" mode="svg" class="size-6" />{{ profile.website }}
+    <Icon name="lucide:link" mode="svg" class="size-6" aria-hidden="true" />
+    <span>{{ profile.website }}</span>
   </NuxtLink>

Apply similar changes to GitHub and Twitter links.

Likely invalid or redundant comment.

@MrSunshyne
Copy link
Member

i reviewed the PR. Looks good to me ! i'll merge it.
PS: I realized the speaker page is actually very badly designed and we need to work on it soon as well to do justice to the newly available data :D something similar to this

@MrSunshyne MrSunshyne merged commit 589ff10 into frontendmu:main Dec 6, 2024
1 check was pending
@christopher-adolphe christopher-adolphe deleted the feature/speaker-profile-bio branch December 10, 2024 03:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants