Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Backend/add_availability_feature_COMPLETE.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
-- ================================================
-- AVAILABILITY STATUS FEATURE - DATABASE SETUP
-- ================================================
-- Run this ENTIRE script in your Supabase SQL Editor
-- Go to: https://supabase.com/dashboard → Your Project → SQL Editor → New Query
-- Copy and paste this entire file, then click "Run"
-- ================================================

-- 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'));
Comment on lines +14 to +21
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.


-- 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
COMMENT ON COLUMN public.users.availability_status IS
'Creator availability status: available (open for work), busy (booked but visible), not_looking (hidden from search)';

COMMENT ON COLUMN public.users.availability_message IS
'Optional custom message shown to brands (max 150 chars). Example: "Available starting January 2026"';

-- Step 5: Update existing users to have default availability
-- This ensures all existing creators show as "available" by default
UPDATE public.users
SET availability_status = 'available'
WHERE availability_status IS NULL;

-- ================================================
-- VERIFICATION: Check if it worked
-- ================================================
-- After running the above, run this query to verify:
-- SELECT id, username, availability_status, availability_message FROM public.users LIMIT 5;

-- ================================================
-- SUCCESS!
-- ================================================
-- You should see:
-- ✓ availability_status column added
-- ✓ availability_message column added
-- ✓ All existing users set to 'available'
--
-- Now refresh your frontend and the feature will work!
-- ================================================
16 changes: 16 additions & 0 deletions Backend/add_availability_status.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- Add availability status 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;

-- 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'));
Comment on lines +7 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.


-- Add index for faster filtering
CREATE INDEX IF NOT EXISTS idx_users_availability ON public.users(availability_status);

-- Add comment for documentation
COMMENT ON COLUMN public.users.availability_status IS 'Creator availability: available, busy, or not_looking';
COMMENT ON COLUMN public.users.availability_message IS 'Optional custom message shown to brands (e.g., "Available starting Jan 2026")';
8 changes: 8 additions & 0 deletions Frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import PublicRoute from "./components/PublicRoute";
import Dashboard from "./pages/Brand/Dashboard";
import BasicDetails from "./pages/BasicDetails";
import Onboarding from "./components/Onboarding";
import ScrollToTop from "./components/ui/scroll-to-top";
import CreatorSearch from "./pages/Brand/CreatorSearch";

function App() {
const [isLoading, setIsLoading] = useState(true);
Expand All @@ -45,6 +47,7 @@ function App() {
return (
<Router>
<AuthProvider>
<ScrollToTop />
<Routes>
{/* Public Routes */}
<Route path="/" element={<HomePage />} />
Expand All @@ -68,6 +71,11 @@ function App() {
<Dashboard />
</ProtectedRoute>
} />
<Route path="/brand/creators" element={
<ProtectedRoute>
<CreatorSearch />
</ProtectedRoute>
} />
<Route path="/basicDetails/:user" element={<BasicDetails />} />
<Route path="/creator/messages" element={<MessagesPage />} />
<Route path="/onboarding" element={
Expand Down
115 changes: 115 additions & 0 deletions Frontend/src/components/AvailabilityBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { CheckCircle, Clock, XCircle } from 'lucide-react';

type AvailabilityStatus = 'available' | 'busy' | 'not_looking';

interface AvailabilityBadgeProps {
status: AvailabilityStatus;
message?: string | null;
size?: 'sm' | 'md' | 'lg';
showMessage?: boolean;
}

/**
* AvailabilityBadge displays a color-coded badge showing creator availability status.
* @param status - The availability status (available/busy/not_looking)
* @param message - Optional custom message to display below badge
* @param size - Badge size variant (sm/md/lg)
* @param showMessage - Whether to display the custom message
*/
export default function AvailabilityBadge({
status,
message,
size = 'md',
showMessage = true
}: AvailabilityBadgeProps) {
/**
* Returns styling configuration based on availability status.
*/
const getConfig = () => {
switch (status) {
case 'available':
return {
icon: CheckCircle,
label: 'Available',
bgColor: 'bg-green-100',
textColor: 'text-green-700',
borderColor: 'border-green-300',
dotColor: 'bg-green-500'
};
case 'busy':
return {
icon: Clock,
label: 'Busy',
bgColor: 'bg-yellow-100',
textColor: 'text-yellow-700',
borderColor: 'border-yellow-300',
dotColor: 'bg-yellow-500'
};
case 'not_looking':
return {
icon: XCircle,
label: 'Not Available',
bgColor: 'bg-gray-100',
textColor: 'text-gray-600',
borderColor: 'border-gray-300',
dotColor: 'bg-gray-500'
};
default:
return {
icon: CheckCircle,
label: 'Available',
bgColor: 'bg-green-100',
textColor: 'text-green-700',
borderColor: 'border-green-300',
dotColor: 'bg-green-500'
};
}
};

/**
* Returns Tailwind CSS classes for the specified badge size.
*/
const getSizeClasses = () => {
switch (size) {
case 'sm':
return {
badge: 'px-2 py-0.5 text-xs',
icon: 'h-3 w-3',
dot: 'h-2 w-2'
};
case 'lg':
return {
badge: 'px-4 py-2 text-base',
icon: 'h-5 w-5',
dot: 'h-3 w-3'
};
default: // md
return {
badge: 'px-3 py-1 text-sm',
icon: 'h-4 w-4',
dot: 'h-2.5 w-2.5'
};
}
};

const config = getConfig();
const sizeClasses = getSizeClasses();
const Icon = config.icon;

return (
<div className="inline-flex flex-col gap-1">
<span
className={`inline-flex items-center gap-1.5 rounded-full font-medium border ${config.bgColor} ${config.textColor} ${config.borderColor} ${sizeClasses.badge}`}
>
<span className={`${config.dotColor} rounded-full ${sizeClasses.dot} animate-pulse`}></span>
<Icon className={sizeClasses.icon} />
{config.label}
</span>
{showMessage && message && (
<span className="text-xs text-gray-600 italic px-2">
"{message}"
</span>
)}
</div>
);
}
Loading