Skip to content
Merged
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
46 changes: 39 additions & 7 deletions frontend/src/components/ui/Tabs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, useContext } from 'react';
import React, { createContext, useContext, useRef, useEffect, useState } from 'react';

const TabsContext = createContext();

Expand All @@ -13,23 +13,55 @@ const Tabs = ({ value, onValueChange, children, className = '' }) => {
};

const TabsList = ({ children, className = '', ...props }) => {
const { value: currentValue } = useContext(TabsContext);
const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 });
const tabsRef = useRef({});

useEffect(() => {
const activeTab = tabsRef.current[currentValue];
if (activeTab) {
setIndicatorStyle({
left: activeTab.offsetLeft,
width: activeTab.offsetWidth,
});
}
}, [currentValue]);
Comment on lines +20 to +28
Copy link

Copilot AI Oct 19, 2025

Choose a reason for hiding this comment

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

The active tab indicator only updates when the selected value changes. After a window resize (or container width change), the indicator can become misaligned because offsetLeft/offsetWidth change but this effect doesn't re-run. Add a resize listener or a ResizeObserver to recompute the indicator on layout changes.

Copilot uses AI. Check for mistakes.

return (
<div className={`inline-flex h-10 items-center justify-center rounded-lg bg-gray-100 p-1 text-gray-500 ${className}`} {...props}>
{children}
<div className={`relative flex h-10 items-center justify-center rounded-lg bg-gray-100 p-1 gap-1 text-gray-500 ${className}`} {...props}>
<div
className="absolute h-8 rounded-md border-2 border-emerald-600 transition-all duration-300 ease-in-out"
style={{
left: `${indicatorStyle.left}px`,
width: `${indicatorStyle.width}px`,
top: '4px',
}}
/>
{React.Children.map(children, (child) =>
React.cloneElement(child, { tabsRef })
)}
</div>
);
};

const TabsTrigger = ({ value, children, className = '', ...props }) => {
const TabsTrigger = ({ value, children, className = '', tabsRef, ...props }) => {
const { value: currentValue, onValueChange } = useContext(TabsContext);
const isActive = currentValue === value;
const buttonRef = useRef(null);

useEffect(() => {
if (tabsRef && buttonRef.current) {
tabsRef.current[value] = buttonRef.current;
}
}, [tabsRef, value]);

return (
<button
Copy link

Copilot AI Oct 19, 2025

Choose a reason for hiding this comment

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

Add type="button" to avoid unintended form submissions if TabsTrigger is ever rendered inside a form.

Suggested change
<button
<button
type="button"

Copilot uses AI. Check for mistakes.
className={`inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ${
ref={buttonRef}
className={`relative flex-1 inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-colors duration-200 focus:outline-none disabled:pointer-events-none disabled:opacity-50 ${
isActive
? 'bg-white text-gray-900 shadow-sm'
: 'hover:bg-white hover:text-gray-900'
? 'text-emerald-700 font-semibold'
: 'text-gray-600 hover:text-gray-900'
} ${className}`}
onClick={() => onValueChange(value)}
{...props}
Comment on lines +60 to 67
Copy link

Copilot AI Oct 19, 2025

Choose a reason for hiding this comment

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

Removing the visible focus ring makes keyboard navigation harder. Restore accessible focus-visible styles (e.g., focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-offset-2) so users can see which tab is focused.

Copilot uses AI. Check for mistakes.
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/Feed.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ const FeedPage = () => {
<div className="container mx-auto px-4 py-6 grid lg:grid-cols-[300px_1fr] gap-6 min-h-screen bg-gray-50">
{/* Sidebar */}
<aside className="space-y-4">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mt-8 sticky top-20">
<div className="flex items-center justify-between mb-4">
<h3 className="font-semibold text-gray-900">Search & Filter</h3>
<button
Expand All @@ -188,7 +188,7 @@ const FeedPage = () => {
{/* Main Content */}
<section className="space-y-6">
{/* Header - Dynamic based on active tab */}
<div className="flex items-center justify-between mt-8">
<div className="flex items-center justify-between mt-8 mb-8">
<div className="flex-1 text-center">
<h1 className="text-2xl font-bold text-gray-900 mb-2">
{currentTabContent.title}
Expand All @@ -211,7 +211,7 @@ const FeedPage = () => {
{/* Tabs */}
<div className="bg-white rounded-lg border border-gray-200 p-4">
<Tabs value={activeTab} onValueChange={handleTabChange}>
<TabsList className="grid w-full max-w-md grid-cols-3">
<TabsList className="w-full max-w-md mx-auto">
{TAB_OPTIONS.map(({ value, label }) => (
<TabsTrigger key={value} value={value}>
{label}
Expand Down
31 changes: 21 additions & 10 deletions frontend/src/pages/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,19 @@ const MessagesPage = () => {
}

return (
<div className="container mx-auto px-4 py-6">
<div className="mb-6">
<div className="container mx-auto" style={{ paddingTop: '6px' }}>
Copy link

Copilot AI Oct 19, 2025

Choose a reason for hiding this comment

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

[nitpick] Avoid inline padding styles; use Tailwind spacing utilities for consistency and theming. Suggest replacing with className="container mx-auto px-4 pt-1.5" to keep horizontal padding consistent with other pages and express 6px as pt-1.5.

Suggested change
<div className="container mx-auto" style={{ paddingTop: '6px' }}>
<div className="container mx-auto px-4 pt-1.5">

Copilot uses AI. Check for mistakes.
<div className="flex justify-start mb-6">
<Button
onClick={() => navigate('/feed')}
variant="ghost"
className="gap-2 mb-4"
className="gap-2"
>
<ArrowLeft className="h-4 w-4" />
Back to Feed
</Button>
</div>

<div className="mb-4">
<h1 className="text-2xl font-bold text-gray-900">Messages</h1>
<p className="text-gray-600">Chat with other users about items</p>
</div>
Expand Down Expand Up @@ -344,16 +347,24 @@ const MessagesPage = () => {
<div
className={`max-w-xs lg:max-w-md px-4 py-2 rounded-lg ${
message.senderId === user.uid
? 'bg-emerald-600 text-white'
? 'bg-emerald-600'
: 'bg-gray-100 text-gray-900'
}`}
>
<p className={`text-sm ${
message.senderId === user.uid ? 'text-white' : 'text-gray-900'
}`}>{message.text}</p>
<p className={`text-xs mt-1 ${
message.senderId === user.uid ? 'text-emerald-100' : 'text-gray-500'
}`}>
<p
className={`text-sm ${
message.senderId === user.uid ? '' : 'text-gray-900'
}`}
style={message.senderId === user.uid ? { color: '#FFFFFF' } : undefined}
>
{message.text}
</p>
<p
className={`text-xs mt-1 ${
message.senderId === user.uid ? '' : 'text-gray-500'
}`}
style={message.senderId === user.uid ? { color: '#FFFFFF' } : undefined}
Comment on lines +355 to +366
Copy link

Copilot AI Oct 19, 2025

Choose a reason for hiding this comment

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

[nitpick] Prefer Tailwind classes over inline color styles for consistency and easier theming. For example: use text-white when senderId matches and text-gray-900/text-gray-500 otherwise, e.g., className={text-sm ${message.senderId === user.uid ? 'text-white' : 'text-gray-900'}} and className={text-xs mt-1 ${message.senderId === user.uid ? 'text-white' : 'text-gray-500'}}.

Suggested change
className={`text-sm ${
message.senderId === user.uid ? '' : 'text-gray-900'
}`}
style={message.senderId === user.uid ? { color: '#FFFFFF' } : undefined}
>
{message.text}
</p>
<p
className={`text-xs mt-1 ${
message.senderId === user.uid ? '' : 'text-gray-500'
}`}
style={message.senderId === user.uid ? { color: '#FFFFFF' } : undefined}
className={`text-sm ${message.senderId === user.uid ? 'text-white' : 'text-gray-900'}`}
>
{message.text}
</p>
<p
className={`text-xs mt-1 ${message.senderId === user.uid ? 'text-white' : 'text-gray-500'}`}

Copilot uses AI. Check for mistakes.
>
{message.timestamp?.toDate?.()?.toLocaleTimeString() || 'Just now'}
</p>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/ProfilePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,10 @@ export default function ProfilePage() {
return
}

// Validate file size (2MB max)
const maxSize = 2 * 1024 * 1024
// Validate file size (5MB max)
const maxSize = 5 * 1024 * 1024
if (file.size > maxSize) {
alert('Image must be less than 2MB')
alert('Image must be less than 5MB')
return
}

Expand Down