Skip to content

Conversation

@sunithvs
Copy link
Owner

@sunithvs sunithvs commented Nov 6, 2025

📋 Overview

This PR implements a comprehensive analytics integration with Supabase, replaces NocoDB with a more robust tracking system, adds localStorage-based modal expiry, and optimizes navigation performance in the GitHub modal.

🎯 Key Features

1. Supabase Analytics Integration

  • ✅ Replaced NocoDB with Supabase edge function integration
  • ✅ Added comprehensive UTM parameter tracking
  • ✅ Implemented referral parameter capture
  • ✅ Background analytics calls (non-blocking UI)

2. SupportModal Improvements

  • ✅ Added localStorage-based expiry system (24-hour cooldown)
  • ✅ First-time visitor detection
  • ✅ Graceful error handling for localStorage edge cases

3. GitHub Modal Navigation Optimization

  • ✅ Instant navigation using window.location.href
  • ✅ Clickable profile cards with differentiated tracking
  • ✅ Search parameter preservation across navigation

🔧 Technical Changes

Modified Files

Core Analytics (www/lib/api.ts)

  • Replaced: addUserToNocodb()addUserToSupabase()
  • Added: UTM parameter capture (utm_source, utm_medium, utm_campaign, utm_term, utm_content)
  • Added: Referral tracking (ref parameter)
  • Added: Social media platform detection with generic URL numbering
  • Added: Type safety improvements (Record<string, string>)

Profile Section (www/components/ProfileSection.tsx)

  • Updated: Function call to use Supabase integration
  • Added: Search parameter handling and conversion
  • Optimized: Background analytics execution (non-blocking)

Page Component (www/app/[username]/page.tsx)

  • Added: Search parameters capture and forwarding
  • Enhanced: Server-side parameter handling

Support Modal (www/components/modal/support-modal.tsx)

  • Added: localStorage expiry system with 24-hour cooldown
  • Added: First-time visitor detection
  • Added: Timestamp-based modal display logic
  • Enhanced: Error handling for localStorage failures

GitHub Modal (www/components/github-modal/client.tsx)

  • Optimized: Navigation performance using window.location.href
  • Added: Clickable profile cards with ref=modelv2
  • Enhanced: Search parameter preservation
  • Improved: Instant navigation feedback

Environment Configuration (www/example.env)

  • Removed: NocoDB environment variables
  • Added: Supabase configuration variables

📊 Data Mapping

Analytics Data Structure

{
  name: "username",
  "full name": "User's Full Name",
  "devb profile": "https://devb.io/username",
  github: "https://github.com/username",
  Linkedin: "linkedin_url",
  twitter: "twitter_url",
  Medium: "medium_url", 
  instagram: "instagram_url",
  devb: "devb_url",
  "generic 1": "first_generic_url",
  "generic 2": "second_generic_url",
  // UTM Parameters (if present)
  utm_source: "source_value",
  utm_medium: "medium_value",
  utm_campaign: "campaign_value", 
  utm_term: "term_value",
  utm_content: "content_value",
  ref: "referral_value"
}

Social Media Detection

  • LinkedIn: linkedin.com URLs → "Linkedin" field
  • Twitter: twitter.com URLs → "twitter" field
  • Medium: medium.com URLs → "Medium" field
  • Instagram: instagram.com URLs → "instagram" field
  • DevB: devb.io URLs → "devb" field
  • Generic: Other URLs → "generic 1", "generic 2", etc.

⚡ Performance Improvements

1. Non-Blocking Analytics

  • Before: Profile loading blocked by analytics call
  • After: Analytics run in background, UI loads immediately

2. Instant Navigation

  • Before: router.push() with async delays
  • After: window.location.href for instant navigation

3. Smart Modal Display

  • Before: Modal showed on every visit
  • After: 24-hour cooldown with localStorage tracking

🔒 Environment Variables

Required Setup

SUPABASE_URL=your_supabase_project_url
SUPABASE_KEY=your_supabase_anon_key

Supabase Edge Function Whitelist

Update your Supabase function to include:

const WHITELIST = [
  "name", "full name", "devb profile", "github",
  "Medium", "Linkedin", "twitter", "instagram", "devb",
  "generic 1", "generic 2", "generic 3", // add more as needed
  "utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content",
  "ref"
];

🧪 Testing

Test Scenarios

  1. First Visit: Modal appears after 4 seconds
  2. Modal Dismissal: Timestamp saved to localStorage
  3. Return Visit: Modal doesn't appear within 24 hours
  4. After Expiry: Modal appears again after 24+ hours
  5. UTM Tracking: Parameters preserved across navigation
  6. GitHub Modal:
    • Profile card click → ref=modelv2
    • View Profile button → ref=modal
  7. Navigation Speed: Instant page transitions

Manual Testing

# Test URLs with UTM parameters
https://devb.io/username?utm_source=twitter&utm_campaign=launch&ref=test

# Expected analytics data should include all parameters

🔮 Future Enhancements

  • Add user preference toggle for modal disable
  • Implement different expiry periods based on engagement
  • Add analytics dashboard for tracking effectiveness
  • Consider A/B testing for modal variations

✅ Checklist

  • Code changes implemented and tested
  • TypeScript errors resolved
  • Performance optimizations applied
  • Error handling implemented
  • Environment variables documented
  • Backward compatibility maintained
  • No breaking changes introduced

🎉 Impact

User Experience

  • ✅ Faster profile page loading
  • ✅ Reduced modal fatigue
  • ✅ Instant navigation feedback
  • ✅ Preserved analytics tracking

Developer Experience

  • ✅ Cleaner analytics integration
  • ✅ Better error handling
  • ✅ Type-safe implementations
  • ✅ Maintainable code structure

@vercel
Copy link
Contributor

vercel bot commented Nov 6, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
devb-io Error Error Nov 6, 2025 7:01pm

@gemini-code-assist
Copy link

Summary of Changes

Hello @sunithvs, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the application's analytics infrastructure by migrating from NocoDB to Supabase, ensuring more robust and non-blocking data collection. Concurrently, it refines the user experience through intelligent modal display logic with a 24-hour cooldown and boosts navigation speed within the GitHub modal, all while maintaining comprehensive tracking of user interactions and referral sources.

Highlights

  • Supabase Analytics Integration: Replaced NocoDB with a Supabase edge function for analytics, including comprehensive UTM and referral parameter tracking, with calls made in the background to avoid blocking the UI.
  • Support Modal Enhancements: Implemented a localStorage-based 24-hour cooldown for the support modal, featuring first-time visitor detection and robust error handling for localStorage operations.
  • GitHub Modal Navigation Optimization: Improved navigation performance within the GitHub modal by using "window.location.href" for instant page transitions, enabling clickable profile cards with distinct tracking, and preserving search parameters.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request does a great job of migrating the analytics from NocoDB to Supabase and optimizing the user experience with faster navigation and smarter modal display logic. The code is well-structured, and the use of a fire-and-forget approach for analytics calls is a good performance choice.

I've left a few suggestions to improve code maintainability by reducing duplication and making some logic more concise. Specifically, I've pointed out opportunities to refactor duplicated functions and repetitive code blocks. These changes should make the codebase even cleaner and easier to manage in the future. Overall, this is a solid set of improvements.

const urlSearchParams = new URLSearchParams();
if (searchParams) {
Object.entries(searchParams).forEach(([key, value]) => {
if (value && typeof value === 'string') {

Choose a reason for hiding this comment

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

medium

The value && check filters out empty strings (e.g., from ?ref=), which might be unintentional as empty strings can be valid parameter values. The typeof value === 'string' check already handles null and undefined. Consider removing value && to allow tracking of parameters with empty values.

Suggested change
if (value && typeof value === 'string') {
if (typeof value === 'string') {

Comment on lines 46 to 67
setLoading(true);
await router.push(`/${profile?.login}?ref=modal`);

// Get current search params and preserve them
const currentParams = new URLSearchParams(window.location.search);
currentParams.set('ref', 'modal');

// Use window.location for instant navigation
window.location.href = `/${profile?.login}?${currentParams.toString()}`;
};

// no need to setLoading(false) because navigation will replace this page
const redirectToProfilePageFromCard = () => {
if (!profile) return;

// Get current search params and preserve them
const currentParams = new URLSearchParams(window.location.search);
currentParams.set('ref', 'modelv2');

// Use window.location for instant navigation
window.location.href = `/${profile?.login}?${currentParams.toString()}`;
};
// Debounce the username input to prevent excessive API calls
const debouncedUsername = useDebounce(username, 500);

Choose a reason for hiding this comment

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

medium

There's code duplication between redirectToProfilePage and redirectToProfilePageFromCard. You can extract the common navigation logic into a helper function to improve maintainability and reduce redundancy.

  const navigateToProfile = (ref: 'modal' | 'modelv2') => {
    if (!profile) return;

    // Get current search params and preserve them
    const currentParams = new URLSearchParams(window.location.search);
    currentParams.set('ref', ref);

    // Use window.location for instant navigation
    window.location.href = `/${profile.login}?${currentParams.toString()}`;
  };

  const redirectToProfilePage = () => {
    setLoading(true);
    navigateToProfile('modal');
  };

  const redirectToProfilePageFromCard = () => {
    navigateToProfile('modelv2');
  };

Comment on lines +12 to +19
// Utility function to detect provider from URL
const detectProvider = (url: string): string => {
const urlLower = url.toLowerCase();
if (urlLower.includes('medium.com')) return 'medium';
if (urlLower.includes('instagram.com')) return 'instagram';
if (urlLower.includes('huggingface.co')) return 'huggingface';
return 'generic';
};

Choose a reason for hiding this comment

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

medium

This detectProvider function is duplicated in www/components/ProfileSection.tsx. To avoid code duplication, it should be centralized in a shared location and imported where needed.

While you're at it, you could improve this function by adding detection for devb.io URLs. This would allow you to simplify the switch statement in addUserToSupabase by creating a separate case "devb": instead of nesting the logic inside the generic case.

Example update for detectProvider:

if (urlLower.includes('devb.io')) return 'devb';

Comment on lines +265 to +281
// UTM parameters
const utmSource = searchParams.get('utm_source');
const utmMedium = searchParams.get('utm_medium');
const utmCampaign = searchParams.get('utm_campaign');
const utmTerm = searchParams.get('utm_term');
const utmContent = searchParams.get('utm_content');

// Referral parameter
const ref = searchParams.get('ref');

// Add to mapped data if they exist
if (utmSource) mappedData['utm_source'] = utmSource;
if (utmMedium) mappedData['utm_medium'] = utmMedium;
if (utmCampaign) mappedData['utm_campaign'] = utmCampaign;
if (utmTerm) mappedData['utm_term'] = utmTerm;
if (utmContent) mappedData['utm_content'] = utmContent;
if (ref) mappedData['ref'] = ref;

Choose a reason for hiding this comment

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

medium

This block of code for handling UTM parameters and ref is repetitive. You can use a loop to make it more concise and easier to maintain if more parameters are added in the future.

Suggested change
// UTM parameters
const utmSource = searchParams.get('utm_source');
const utmMedium = searchParams.get('utm_medium');
const utmCampaign = searchParams.get('utm_campaign');
const utmTerm = searchParams.get('utm_term');
const utmContent = searchParams.get('utm_content');
// Referral parameter
const ref = searchParams.get('ref');
// Add to mapped data if they exist
if (utmSource) mappedData['utm_source'] = utmSource;
if (utmMedium) mappedData['utm_medium'] = utmMedium;
if (utmCampaign) mappedData['utm_campaign'] = utmCampaign;
if (utmTerm) mappedData['utm_term'] = utmTerm;
if (utmContent) mappedData['utm_content'] = utmContent;
if (ref) mappedData['ref'] = ref;
const paramsToTrack = [
'utm_source',
'utm_medium',
'utm_campaign',
'utm_term',
'utm_content',
'ref',
];
paramsToTrack.forEach((param) => {
const value = searchParams.get(param);
if (value) {
mappedData[param] = value;
}
});

@sunithvs sunithvs merged commit 8e7b870 into main Nov 6, 2025
2 of 3 checks passed
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