-
Notifications
You must be signed in to change notification settings - Fork 110
Feature: creator availability status #210
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
base: main
Are you sure you want to change the base?
Feature: creator availability status #210
Conversation
- Created ScrollToTop component with smooth animations - Added circular progress ring showing scroll position - Gradient purple design with hover effects and tooltip - Optimized scroll event handling with requestAnimationFrame - WCAG compliant with proper ARIA attributes - Responsive and mobile-friendly Closes AOSSIE-Org#204
- Add requestAnimationFrame throttling for scroll events - Fix division by zero on non-scrollable pages - Calculate SVG radius dynamically to match rendered size - Add proper cleanup and accessibility attributes
|
Warning Rate limit exceeded@Swaim-Sahay has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 29 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughAdds a creator availability feature: DB migration adds availability columns, constraint, index, and comments; frontend adds availability badge, toggle, creator card, search page, scroll-to-top UI, route, and dashboard integration so creators can set status/message and brands can filter/search by availability. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Brand as Browser (Brand UI)
participant Frontend as Web App (React)
participant Supabase as Supabase (Postgres)
Note over Brand,Frontend: Brand searches or views creators
Brand->>Frontend: Navigate to /brand/creators or set filters
Frontend->>Supabase: SELECT users WHERE role='creator' + availability filter
Supabase-->>Frontend: Return creators (incl. availability_status, availability_message, social_profiles)
Frontend->>Brand: Render CreatorCard grid with AvailabilityBadge
Note over Brand,Frontend: Creator updates availability from Dashboard
Brand->>Frontend: Interact with AvailabilityToggle (change status/message)
Frontend->>Supabase: UPDATE users SET availability_status/message
Supabase-->>Frontend: OK / Error
Frontend->>Brand: Update preview & UI or show error
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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: 5
🧹 Nitpick comments (7)
Backend/add_availability_feature_COMPLETE.sql (1)
31-32: Consider adding a length constraint on availability_message.The comment documents a 150-character limit, but no database constraint enforces it. If this limit is intentional, add a CHECK constraint or change the column type.
-- Option 1: Add CHECK constraint ALTER TABLE public.users ADD CONSTRAINT check_availability_message_length CHECK (char_length(availability_message) <= 150); -- Option 2: Use VARCHAR instead ALTER TABLE public.users ALTER COLUMN availability_message TYPE VARCHAR(150);Frontend/src/pages/Brand/CreatorSearch.tsx (3)
63-65: Error handling lacks user feedback.Errors are only logged to console. Users won't know if the fetch failed. Consider showing an error state or toast notification.
+ const [error, setError] = useState<string | null>(null); + useEffect(() => { const loadCreators = async () => { setLoading(true); + setError(null); try { // ... existing query logic } catch (error) { console.error('Error loading creators:', error); + setError('Failed to load creators. Please try again.'); } finally { setLoading(false); } }; // ... }, [availabilityFilter]);Then render the error state in the UI alongside the loading/empty states.
147-150: Placeholder callback should be implemented or removed.The
onViewProfilecallback only logs to console. Either implement navigation to the creator's profile or remove the callback if the feature is not ready.+ import { useNavigate } from 'react-router-dom'; + export default function BrandCreatorSearch() { + const navigate = useNavigate(); // ... <CreatorCard key={creator.id} creator={creator} - onViewProfile={(id: string) => { - // Navigate to creator profile - console.log('View profile:', id); - }} + onViewProfile={(id: string) => navigate(`/basicDetails/${id}`)} />
6-19: Consider extracting Creator type to a shared location.The
Creatorinterface duplicates structure likely used in other components (CreatorCard, AvailabilityToggle). Extracting to a shared types file would improve maintainability.Create a shared type file:
// Frontend/src/types/creator.ts export interface Creator { id: string; username: string; profile_image: string | null; category: string; country: string; availability_status: 'available' | 'busy' | 'not_looking'; availability_message?: string | null; social_profiles?: Array<{ platform: string; followers?: number; subscriber_count?: number; }>; }Frontend/src/components/AvailabilityToggle.tsx (2)
161-161: Avoid redundant updates when status hasn't changed.Clicking the currently selected status button triggers a database update even though nothing has changed. This creates unnecessary network traffic and potential UI flicker.
Apply this diff:
- onClick={() => updateAvailability(status)} + onClick={() => { + if (availability.status !== status) { + updateAvailability(status); + } + }}
200-200: Avoid redundant updates on blur without changes.The
onBlurhandler triggers an update every time the textarea loses focus, even if the message hasn't changed since the last save. This creates unnecessary backend calls.Consider tracking the last saved message and only updating if it differs:
+ const [lastSavedMessage, setLastSavedMessage] = useState(''); + // In loadAvailability success path: + setLastSavedMessage(data.availability_message || ''); + // In updateAvailability success path: + setLastSavedMessage(newMessage !== undefined ? newMessage : availability.message); + // In the textarea: - onBlur={() => updateAvailability(availability.status, availability.message)} + onBlur={() => { + if (availability.message !== lastSavedMessage) { + updateAvailability(availability.status, availability.message); + } + }}Frontend/src/components/CreatorCard.tsx (1)
102-117: Consider extracting button configuration to reduce duplication.The availability status is checked twice—once for styling (lines 105-110) and once for the label (lines 112-116). This creates maintenance overhead and potential inconsistency.
Consider this refactor:
+ const buttonConfig = (() => { + switch (creator.availability_status) { + case 'available': + return { + className: 'bg-purple-600 hover:bg-purple-700 text-white', + label: 'Contact Creator' + }; + case 'busy': + return { + className: 'bg-yellow-100 hover:bg-yellow-200 text-yellow-700', + label: 'View Profile' + }; + default: + return { + className: 'bg-gray-200 hover:bg-gray-300 text-gray-600', + label: 'View Profile Only' + }; + } + })(); + <button onClick={() => onViewProfile?.(creator.id)} - className={`w-full py-2 px-4 rounded-lg font-medium transition-colors ${ - creator.availability_status === 'available' - ? 'bg-purple-600 hover:bg-purple-700 text-white' - : creator.availability_status === 'busy' - ? 'bg-yellow-100 hover:bg-yellow-200 text-yellow-700' - : 'bg-gray-200 hover:bg-gray-300 text-gray-600' - }`} + className={`w-full py-2 px-4 rounded-lg font-medium transition-colors ${buttonConfig.className}`} > - {creator.availability_status === 'available' - ? 'Contact Creator' - : creator.availability_status === 'busy' - ? 'View Profile' - : 'View Profile Only'} + {buttonConfig.label} </button>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
Backend/add_availability_feature_COMPLETE.sql(1 hunks)Backend/add_availability_status.sql(1 hunks)Frontend/src/App.tsx(3 hunks)Frontend/src/components/AvailabilityBadge.tsx(1 hunks)Frontend/src/components/AvailabilityToggle.tsx(1 hunks)Frontend/src/components/CreatorCard.tsx(1 hunks)Frontend/src/components/ui/scroll-to-top.tsx(1 hunks)Frontend/src/pages/Brand/CreatorSearch.tsx(1 hunks)Frontend/src/pages/DashboardPage.tsx(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
Frontend/src/components/CreatorCard.tsx (1)
Frontend/src/components/AvailabilityBadge.tsx (1)
AvailabilityBadge(12-102)
Frontend/src/pages/Brand/CreatorSearch.tsx (2)
Frontend/src/utils/supabase.tsx (1)
supabase(11-11)Frontend/src/components/CreatorCard.tsx (1)
CreatorCard(22-121)
Frontend/src/components/AvailabilityToggle.tsx (2)
Frontend/src/context/AuthContext.tsx (1)
useAuth(216-222)Frontend/src/utils/supabase.tsx (1)
supabase(11-11)
Frontend/src/App.tsx (1)
Frontend/src/components/ui/scroll-to-top.tsx (1)
ScrollToTop(4-134)
Frontend/src/pages/DashboardPage.tsx (1)
Frontend/src/components/AvailabilityToggle.tsx (1)
AvailabilityToggle(13-228)
🔇 Additional comments (15)
Frontend/src/components/ui/scroll-to-top.tsx (1)
4-66: Good implementation of scroll-to-top with performance optimizations.The component correctly uses
requestAnimationFramethrottling and passive event listeners for scroll handling. Cleanup on unmount is properly handled. Accessibility attributes are appropriate.Frontend/src/App.tsx (2)
23-24: LGTM - ScrollToTop and CreatorSearch integration.The imports and component placement are correct. ScrollToTop is rendered globally inside AuthProvider, and the new
/brand/creatorsroute follows the existing protected route pattern.Also applies to: 50-50
74-78: Route follows established patterns.The new
/brand/creatorsroute is correctly wrapped withProtectedRouteand follows the existing route structure.Frontend/src/pages/DashboardPage.tsx (2)
117-120: AvailabilityToggle integration looks correct.The component is placed appropriately at the top of the Overview tab content. Based on the component summary, it handles its own loading state internally.
42-42: Verify if "Find Creators" link is appropriate for this dashboard.This dashboard appears to be creator-focused (showing creator metrics like "Total Revenue", "Sponsorships", etc.), but "Find Creators" (
/brand/creators) is a brand feature. Confirm whether this link should only appear for brand users, if this dashboard serves both creator and brand roles, or if there's a legitimate cross-role workflow that justifies its presence here.Frontend/src/pages/Brand/CreatorSearch.tsx (1)
27-71: Data fetching and filtering logic is well-structured.The implementation correctly:
- Excludes
not_lookingcreators from search per requirements- Uses server-side filtering for availability status
- Performs client-side filtering for search term (appropriate for reasonable dataset sizes)
- Properly handles the async function with
void loadCreators()Frontend/src/components/AvailabilityToggle.tsx (3)
90-123: LGTM!The status configuration mapping is well-structured and provides clear visual feedback for each availability state. The use of semantic colors and icons enhances usability.
125-134: LGTM!The loading skeleton provides good UX while data is being fetched, preventing layout shift and giving users visual feedback.
72-72: Verify existence of referenced guide file.The alert messages reference
AVAILABILITY_STATUS_GUIDE.md, which may not exist in the repository. This could confuse users who encounter the error. Ensure the guide file exists at the repository root or update the alert message with the correct path to the documentation.Backend/add_availability_status.sql (2)
1-4: LGTM!The columns are added safely with
IF NOT EXISTSand appropriate defaults. UsingTEXTwith a constraint is a good pattern, and defaulting to 'available' aligns with the feature requirements.
11-16: LGTM!The index on
availability_statuswill improve query performance for filtering creators by availability, and the documentation comments provide clear context for future maintainers.Frontend/src/components/AvailabilityBadge.tsx (1)
1-102: LGTM!The component is well-structured with:
- Clear separation of configuration logic (getConfig, getSizeClasses)
- Proper default cases to handle unexpected values
- Type-safe props with sensible defaults
- Responsive size variants
- Clean, accessible UI with animated pulse effect
The implementation aligns well with the PR objectives for displaying availability badges.
Frontend/src/components/CreatorCard.tsx (3)
23-25: LGTM!The follower aggregation logic correctly handles both
followersandsubscriber_countproperties, with a sensible fallback to 0. The use of reduce is appropriate here.
52-59: LGTM!The AvailabilityBadge is well-positioned in the top-right corner of the header with appropriate size and showMessage settings for the card context.
46-46: Verify default avatar asset exists.The fallback
/default-avatar.pngassumes a public asset exists at that path. If it doesn't, users will see a broken image icon.Run the following script to check if the default avatar exists:
#!/bin/bash # Check for default avatar in public directory fd -t f "default-avatar.png" public/If it doesn't exist, consider:
- Adding the asset to the
public/directory, or- Using a data URI or SVG placeholder, or
- Using a service like
ui-avatars.comas a fallback
| -- Step 2: Add validation constraint | ||
| -- Drop existing constraint if it exists (in case you're re-running this) | ||
| ALTER TABLE public.users DROP CONSTRAINT IF EXISTS check_availability_status; | ||
|
|
||
| -- Add the constraint with valid values | ||
| ALTER TABLE public.users | ||
| ADD CONSTRAINT check_availability_status | ||
| CHECK (availability_status IN ('available', 'busy', 'not_looking')); |
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.
Constraint may fail on existing data with NULL values.
The CHECK constraint is added before the UPDATE that sets NULL values to 'available'. If the table has existing rows, they will have NULL in the new column (PostgreSQL ADD COLUMN with DEFAULT doesn't backfill existing rows in older versions). The constraint will reject NULL values, causing the migration to fail.
Reorder to update before adding the constraint:
-- Step 1: Add the new columns to users table
ALTER TABLE public.users
ADD COLUMN IF NOT EXISTS availability_status TEXT DEFAULT 'available',
ADD COLUMN IF NOT EXISTS availability_message TEXT DEFAULT NULL;
--- Step 2: Add validation constraint
--- Drop existing constraint if it exists (in case you're re-running this)
-ALTER TABLE public.users DROP CONSTRAINT IF EXISTS check_availability_status;
-
--- Add the constraint with valid values
-ALTER TABLE public.users
-ADD CONSTRAINT check_availability_status
-CHECK (availability_status IN ('available', 'busy', 'not_looking'));
-
--- Step 3: Create index for faster filtering
-CREATE INDEX IF NOT EXISTS idx_users_availability
-ON public.users(availability_status);
-
--- Step 4: Add helpful comments for documentation
-...
-
--- Step 5: Update existing users to have default availability
+-- Step 2: Update existing users to have default availability (BEFORE adding constraint)
UPDATE public.users
SET availability_status = 'available'
WHERE availability_status IS NULL;
+
+-- Step 3: Add validation constraint
+ALTER TABLE public.users DROP CONSTRAINT IF EXISTS check_availability_status;
+ALTER TABLE public.users
+ADD CONSTRAINT check_availability_status
+CHECK (availability_status IN ('available', 'busy', 'not_looking'));
+
+-- Step 4: Create index for faster filtering
+CREATE INDEX IF NOT EXISTS idx_users_availability
+ON public.users(availability_status);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In Backend/add_availability_feature_COMPLETE.sql around lines 14 to 21, the
CHECK constraint is added before existing NULL values are set to 'available',
which will cause the migration to fail; reorder the steps so you first add the
column (with or without a default), then UPDATE existing rows to set NULL values
to 'available' (or another desired default), and only after existing rows are
backfilled add the CHECK constraint (or replace an interim relaxed constraint
like allowing NULLs with the strict CHECK after backfill). Ensure the migration
updates existing data before enforcing the constraint.
| ALTER TABLE public.users | ||
| ADD CONSTRAINT check_availability_status | ||
| CHECK (availability_status IN ('available', 'busy', 'not_looking')); |
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.
CHECK constraint will fail on re-run.
The ADD CONSTRAINT statement doesn't use IF NOT EXISTS (not supported in standard PostgreSQL for constraints). If this script is executed twice, it will fail with a duplicate constraint error.
Consider using this safer pattern:
-- Add check constraint to ensure valid status values
-ALTER TABLE public.users
-ADD CONSTRAINT check_availability_status
-CHECK (availability_status IN ('available', 'busy', 'not_looking'));
+DO $$
+BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM pg_constraint
+ WHERE conname = 'check_availability_status'
+ ) THEN
+ ALTER TABLE public.users
+ ADD CONSTRAINT check_availability_status
+ CHECK (availability_status IN ('available', 'busy', 'not_looking'));
+ END IF;
+END $$;Or use DROP CONSTRAINT IF EXISTS before adding:
ALTER TABLE public.users DROP CONSTRAINT IF EXISTS check_availability_status;
ALTER TABLE public.users ADD CONSTRAINT check_availability_status
CHECK (availability_status IN ('available', 'busy', 'not_looking'));🤖 Prompt for AI Agents
In Backend/add_availability_status.sql around lines 7-9, the ALTER TABLE ADD
CONSTRAINT will error on subsequent runs because PostgreSQL has no IF NOT EXISTS
for constraints; modify the script to first remove any existing constraint and
then add it (i.e., perform a DROP CONSTRAINT IF EXISTS for
check_availability_status before the ADD CONSTRAINT), or alternatively guard the
ADD by querying pg_constraint/pg_catalog to only create the constraint when it
does not already exist.
| useEffect(() => { | ||
| const loadAvailability = async () => { | ||
| try { | ||
| const { data, error } = await supabase | ||
| .from('users') | ||
| .select('availability_status, availability_message') | ||
| .eq('id', user?.id) | ||
| .single(); | ||
|
|
||
| if (error) { | ||
| console.error('Error loading availability:', error); | ||
| // If columns don't exist, just use defaults | ||
| setAvailability({ status: 'available', message: '' }); | ||
| return; | ||
| } | ||
|
|
||
| if (data) { | ||
| setAvailability({ | ||
| status: data.availability_status || 'available', | ||
| message: data.availability_message || '' | ||
| }); | ||
| setShowMessage(!!data.availability_message); | ||
| } | ||
| } catch (error) { | ||
| console.error('Error loading availability:', error); | ||
| setAvailability({ status: 'available', message: '' }); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }; | ||
|
|
||
| if (user) { | ||
| void loadAvailability(); | ||
| } | ||
| }, [user]); |
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.
Guard against null user in data fetch.
The useEffect checks if (user) before calling loadAvailability, but the query at lines 26-30 uses user?.id which could still be undefined if user exists but has no id. This would cause a query with eq('id', undefined).
Apply this diff to add an explicit guard:
- if (user) {
+ if (user?.id) {
void loadAvailability();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| const loadAvailability = async () => { | |
| try { | |
| const { data, error } = await supabase | |
| .from('users') | |
| .select('availability_status, availability_message') | |
| .eq('id', user?.id) | |
| .single(); | |
| if (error) { | |
| console.error('Error loading availability:', error); | |
| // If columns don't exist, just use defaults | |
| setAvailability({ status: 'available', message: '' }); | |
| return; | |
| } | |
| if (data) { | |
| setAvailability({ | |
| status: data.availability_status || 'available', | |
| message: data.availability_message || '' | |
| }); | |
| setShowMessage(!!data.availability_message); | |
| } | |
| } catch (error) { | |
| console.error('Error loading availability:', error); | |
| setAvailability({ status: 'available', message: '' }); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| if (user) { | |
| void loadAvailability(); | |
| } | |
| }, [user]); | |
| useEffect(() => { | |
| const loadAvailability = async () => { | |
| try { | |
| const { data, error } = await supabase | |
| .from('users') | |
| .select('availability_status, availability_message') | |
| .eq('id', user?.id) | |
| .single(); | |
| if (error) { | |
| console.error('Error loading availability:', error); | |
| // If columns don't exist, just use defaults | |
| setAvailability({ status: 'available', message: '' }); | |
| return; | |
| } | |
| if (data) { | |
| setAvailability({ | |
| status: data.availability_status || 'available', | |
| message: data.availability_message || '' | |
| }); | |
| setShowMessage(!!data.availability_message); | |
| } | |
| } catch (error) { | |
| console.error('Error loading availability:', error); | |
| setAvailability({ status: 'available', message: '' }); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| if (user?.id) { | |
| void loadAvailability(); | |
| } | |
| }, [user]); |
🤖 Prompt for AI Agents
In Frontend/src/components/AvailabilityToggle.tsx around lines 23 to 57, the
data fetch uses user?.id which can be undefined even when user exists; guard
explicitly for a valid user.id before running the Supabase query and return
early if missing. Update the useEffect to check if user and user.id are present
(e.g., if (!user || !user.id) { setLoading(false); return; }) before calling
loadAvailability or, inside loadAvailability, validate user.id at the start and
skip the query (setting sensible defaults) when it's absent.
| const updateAvailability = async (newStatus: AvailabilityStatus, newMessage?: string) => { | ||
| setSaving(true); | ||
| try { | ||
| const { error } = await supabase | ||
| .from('users') | ||
| .update({ | ||
| availability_status: newStatus, | ||
| availability_message: newMessage || availability.message || null | ||
| }) | ||
| .eq('id', user?.id); | ||
|
|
||
| if (error) { | ||
| console.error('Error updating availability:', error); | ||
| alert(`Failed to update availability status.\n\nError: ${error.message}\n\nPlease run the SQL migration in Supabase first. Check AVAILABILITY_STATUS_GUIDE.md for instructions.`); | ||
| setSaving(false); | ||
| return; | ||
| } | ||
|
|
||
| setAvailability({ | ||
| status: newStatus, | ||
| message: newMessage !== undefined ? newMessage : availability.message | ||
| }); | ||
| } catch (error) { | ||
| console.error('Error updating availability:', error); | ||
| const errorMessage = error instanceof Error ? error.message : 'Unknown error'; | ||
| alert(`Failed to update availability status.\n\nError: ${errorMessage}\n\nPlease run the SQL migration in Supabase first.`); | ||
| } finally { | ||
| setSaving(false); | ||
| } | ||
| }; |
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.
Guard against null user in updates.
The updateAvailability function uses user?.id at lines 66 and 68, which could be undefined if the user object exists without an id property, leading to a failed database query.
Apply this diff to add an early return:
const updateAvailability = async (newStatus: AvailabilityStatus, newMessage?: string) => {
+ if (!user?.id) {
+ console.error('Cannot update availability: user ID is missing');
+ return;
+ }
setSaving(true);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const updateAvailability = async (newStatus: AvailabilityStatus, newMessage?: string) => { | |
| setSaving(true); | |
| try { | |
| const { error } = await supabase | |
| .from('users') | |
| .update({ | |
| availability_status: newStatus, | |
| availability_message: newMessage || availability.message || null | |
| }) | |
| .eq('id', user?.id); | |
| if (error) { | |
| console.error('Error updating availability:', error); | |
| alert(`Failed to update availability status.\n\nError: ${error.message}\n\nPlease run the SQL migration in Supabase first. Check AVAILABILITY_STATUS_GUIDE.md for instructions.`); | |
| setSaving(false); | |
| return; | |
| } | |
| setAvailability({ | |
| status: newStatus, | |
| message: newMessage !== undefined ? newMessage : availability.message | |
| }); | |
| } catch (error) { | |
| console.error('Error updating availability:', error); | |
| const errorMessage = error instanceof Error ? error.message : 'Unknown error'; | |
| alert(`Failed to update availability status.\n\nError: ${errorMessage}\n\nPlease run the SQL migration in Supabase first.`); | |
| } finally { | |
| setSaving(false); | |
| } | |
| }; | |
| const updateAvailability = async (newStatus: AvailabilityStatus, newMessage?: string) => { | |
| if (!user?.id) { | |
| console.error('Cannot update availability: user ID is missing'); | |
| return; | |
| } | |
| setSaving(true); | |
| try { | |
| const { error } = await supabase | |
| .from('users') | |
| .update({ | |
| availability_status: newStatus, | |
| availability_message: newMessage || availability.message || null | |
| }) | |
| .eq('id', user?.id); | |
| if (error) { | |
| console.error('Error updating availability:', error); | |
| alert(`Failed to update availability status.\n\nError: ${error.message}\n\nPlease run the SQL migration in Supabase first. Check AVAILABILITY_STATUS_GUIDE.md for instructions.`); | |
| setSaving(false); | |
| return; | |
| } | |
| setAvailability({ | |
| status: newStatus, | |
| message: newMessage !== undefined ? newMessage : availability.message | |
| }); | |
| } catch (error) { | |
| console.error('Error updating availability:', error); | |
| const errorMessage = error instanceof Error ? error.message : 'Unknown error'; | |
| alert(`Failed to update availability status.\n\nError: ${errorMessage}\n\nPlease run the SQL migration in Supabase first.`); | |
| } finally { | |
| setSaving(false); | |
| } | |
| }; |
🤖 Prompt for AI Agents
Frontend/src/components/AvailabilityToggle.tsx around lines 59 to 88: the
updateAvailability function uses user?.id in the DB query which can be undefined
and cause a failed query; add an early guard at the top of the function that
checks if user?.id is falsy and if so logs an error (or alerts), sets saving to
false, and returns immediately to avoid running the supabase update; ensure this
guard is placed before any async calls so the function exits cleanly when there
is no valid user id.
| <circle | ||
| cx="50%" | ||
| cy="50%" | ||
| r="45%" | ||
| fill="none" | ||
| stroke="rgba(255, 255, 255, 0.2)" | ||
| strokeWidth="2" | ||
| /> | ||
| <circle | ||
| cx="50%" | ||
| cy="50%" | ||
| r="45%" | ||
| fill="none" | ||
| stroke="white" | ||
| strokeWidth="2" | ||
| strokeDasharray={circumference} | ||
| strokeDashoffset={offset} | ||
| strokeLinecap="round" | ||
| className="transition-all duration-300" | ||
| /> |
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.
SVG radius mismatch between percentage and pixel calculations.
The circles use r="45%" (percentage-based), but strokeDasharray and strokeDashoffset are calculated using circleRadius derived from getBoundingClientRect() pixel dimensions. This mismatch causes the progress arc to not align correctly with the visible circle.
Use consistent units - either compute the actual pixel radius matching the 45% or use a fixed radius:
- const circumference = 2 * Math.PI * circleRadius;
+ // Match the 45% radius used in the SVG circles
+ const svgSize = svgRef.current?.getBoundingClientRect();
+ const actualRadius = svgSize ? Math.min(svgSize.width, svgSize.height) * 0.45 / 2 : 20;
+ const circumference = 2 * Math.PI * actualRadius;Alternatively, use a fixed numeric radius in the SVG instead of percentages for simpler calculations.
Committable suggestion skipped: line range outside the PR's diff.
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: 2
♻️ Duplicate comments (2)
Frontend/src/components/AvailabilityToggle.tsx (2)
62-64: Guard should checkuser?.idnot justuser.The guard condition checks
if (user)but the query at line 37 usesuser?.id. Ifuserexists without anid, the query would useeq('id', undefined).This was previously flagged. Apply the suggested fix:
if (user?.id).
72-73: Missing guard foruser?.idbefore database update.The function uses
user?.idat line 81 without verifying it exists. If undefined, the update would silently fail or affect no rows.This was previously flagged. Add an early return:
if (!user?.id) { setSaving(false); return; }.
🧹 Nitpick comments (2)
Frontend/src/components/CreatorCard.tsx (2)
92-100: Prefer stable keys over array indices.Using array indices as React keys can cause issues if the list order changes. Consider using the platform name or a composite key for better stability.
Apply this diff:
- {creator.social_profiles?.map((profile, idx) => ( + {creator.social_profiles?.map((profile) => ( <div - key={idx} + key={profile.platform} className="p-1.5 bg-gray-100 rounded-full text-gray-600" title={profile.platform} >
104-120: Consider disabling the button when onViewProfile is undefined.The button is clickable even when
onViewProfileis not provided. While optional chaining prevents errors, users experience a non-functional button. Consider conditionally disabling the button or adjusting its appearance.Example implementation:
<button onClick={() => onViewProfile?.(creator.id)} disabled={!onViewProfile} className={`w-full py-2 px-4 rounded-lg font-medium transition-colors ${ !onViewProfile ? 'bg-gray-300 text-gray-500 cursor-not-allowed' : creator.availability_status === 'available' ? 'bg-purple-600 hover:bg-purple-700 text-white' : creator.availability_status === 'busy' ? 'bg-yellow-100 hover:bg-yellow-200 text-yellow-700' : 'bg-gray-200 hover:bg-gray-300 text-gray-600' }`} > {/* ... button text ... */} </button>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
Frontend/src/components/AvailabilityBadge.tsx(1 hunks)Frontend/src/components/AvailabilityToggle.tsx(1 hunks)Frontend/src/components/CreatorCard.tsx(1 hunks)Frontend/src/pages/Brand/CreatorSearch.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- Frontend/src/components/AvailabilityBadge.tsx
- Frontend/src/pages/Brand/CreatorSearch.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
Frontend/src/components/CreatorCard.tsx (1)
Frontend/src/components/AvailabilityBadge.tsx (1)
AvailabilityBadge(19-115)
Frontend/src/components/AvailabilityToggle.tsx (2)
Frontend/src/context/AuthContext.tsx (1)
useAuth(216-222)Frontend/src/utils/supabase.tsx (1)
supabase(11-11)
🔇 Additional comments (5)
Frontend/src/components/AvailabilityToggle.tsx (1)
215-222: Textarea auto-save on blur is reasonable, consider potential rapid interactions.The
onBlurhandler triggers a save, which works well for auto-save UX. However, if a user changes status while the textarea is focused and then blurs, two near-simultaneous updates could occur. The current implementation handles this acceptably since both updates use the same status value from state at call time.Frontend/src/components/CreatorCard.tsx (4)
1-2: LGTM!Clean imports with all dependencies properly referenced in the component.
4-20: LGTM!The interface is well-structured and correctly typed. The availability_status union type aligns with the three states from the PR objectives, and the social_profiles structure accommodates different platforms with their respective metrics.
27-41: LGTM!The helper function correctly maps platform names to icons with case-insensitive matching and safely returns null for unsupported platforms.
49-49: Verify the fallback image path exists.The fallback uses
/default-avatar.png, which assumes this asset is in the public root. Ensure this file exists, or consider using a data URI or an asset imported from the src directory to guarantee availability.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
Raised a PR here here #210 .Please review and let me know if any further changes required. |
closes #209
What this does
Lets creators show if they're available for work. Shows up as a toggle on their dashboard with 3 options (Available/Busy/Not Looking) and optional custom message.
Brands see a colored badge on creator profiles and can filter search by availability.
Files changed
Frontend:
Backend:
Testing done
Before merging
Run the SQL migration in
Backend/add_availability_feature_COMPLETE.sqlto add the database columns.Preview
Screen.Recording.2025-12-02.at.5.57.10.PM.mov
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.