Files
marketplace/client/src/pages/MyOffersPage.tsx
delta-lynx-89e8 b37b734c82 Initial marketplace implementation
Full-stack marketplace for buying/selling second-hand items.
React 19 + TypeScript + Tailwind CSS v4 frontend with 17 screens,
Express + Prisma + Socket.io backend, Stripe payments, JWT auth.

Deployed at https://marketplace.173.212.212.157.sslip.io/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:00:44 -08:00

75 lines
3.3 KiB
TypeScript

import { useState } from 'react';
import { GradientButton } from '../components/ui/GradientButton';
import { Button } from '../components/ui/Button';
import { Badge } from '../components/ui/Badge';
import { Avatar } from '../components/ui/Avatar';
import { mockOffers } from '../utils/mockData';
import { formatCurrency, formatDate } from '../utils/format';
export function MyOffersPage() {
const [sortBy] = useState('newest');
return (
<div>
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-2xl font-bold text-gray-900">My Offers</h1>
<p className="text-sm text-gray-500 mt-1">Review and manage incoming offers on your items</p>
</div>
<select value={sortBy} className="px-3 py-2 rounded-xl border border-gray-200 text-sm bg-white focus:outline-none">
<option value="newest">Sort: Most Recent</option>
<option value="price_high">Highest Offer</option>
<option value="price_low">Lowest Offer</option>
</select>
</div>
<div className="space-y-3">
{mockOffers.map(offer => {
const savings = offer.listing.price - offer.amount;
const statusVariant = offer.status === 'ACCEPTED' ? 'success' : offer.status === 'DECLINED' ? 'error' : offer.status === 'COUNTERED' ? 'warning' : 'info';
return (
<div key={offer.id} className="bg-white rounded-2xl border border-gray-100 p-4 flex items-center gap-4">
{/* Item thumbnail */}
<div className="w-16 h-16 rounded-xl bg-gradient-to-br from-primary-50 to-pink-50 flex items-center justify-center flex-shrink-0">
<span className="text-2xl">
{offer.listing.category === 'FURNITURE' ? '\uD83E\uDE91' : offer.listing.category === 'ELECTRONICS' ? '\uD83C\uDFA7' : '\uD83D\uDCE6'}
</span>
</div>
{/* Info */}
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 truncate">{offer.listing.title}</h3>
<div className="flex items-center gap-2 mt-1">
<Avatar name={offer.buyer.fullName} size="sm" />
<span className="text-xs text-gray-500">{offer.buyer.fullName}</span>
<span className="text-xs text-gray-400">{formatDate(offer.createdAt)}</span>
</div>
</div>
{/* Prices */}
<div className="text-right flex-shrink-0">
<p className="text-xs text-gray-400 line-through">{formatCurrency(offer.listing.price)}</p>
<p className="text-lg font-bold text-primary-600">{formatCurrency(offer.amount)}</p>
<Badge variant="error" size="sm">-{formatCurrency(savings)}</Badge>
</div>
{/* Status / Actions */}
<div className="flex items-center gap-2 flex-shrink-0">
{offer.status === 'PENDING' ? (
<>
<Button variant="secondary" size="sm">Accept</Button>
<GradientButton size="sm">Counteroffer</GradientButton>
</>
) : (
<Badge variant={statusVariant} size="md">{offer.status}</Badge>
)}
</div>
</div>
);
})}
</div>
</div>
);
}